Created
April 21, 2019 17:51
-
-
Save dhemery/6296673e08df382d58351da2aeb71e25 to your computer and use it in GitHub Desktop.
Effects of Different Ways of Expressing Type Dependence in Generic Methods
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.dhemery.generics; | |
import java.util.Objects; | |
import java.util.function.Predicate; | |
public class GenericMethodTypeInference { | |
// Subject type and predicate input type must be the same. | |
<S> boolean test(S subject, Predicate<S> criterion) { | |
return criterion.test(subject); | |
} | |
// Subject type must be subtype of predicate input type. | |
<C, S extends C> boolean boundedTest(S subject, Predicate<C> criterion) { | |
return criterion.test(subject); | |
} | |
// Predicate input type must be supertype of subject type. | |
<S> boolean wildcardTest(S subject, Predicate<? super S> criterion) { | |
return criterion.test(subject); | |
} | |
public void applyTests() { | |
// S <-- Integer (compiler infers that S is Integer) | |
test(3, (Integer i) -> i != null); | |
// S <-- Object | |
test(3, (Object i) -> i != null); | |
// S <-- Integer | |
test(3, Objects::nonNull); | |
// S <-- Integer | |
wildcardTest(3, (Integer i) -> i != null); | |
// S <-- Integer | |
wildcardTest(3, (Object i) -> i != null); | |
// S <-- Integer | |
wildcardTest(3, Objects::nonNull); | |
// S <-- Integer, C <-- Integer | |
boundedTest(3, (Integer i) -> i != null); | |
// S <-- Integer, C <-- Object | |
boundedTest(3, (Object i) -> i != null); | |
// S <-- Integer, C <-- Integer | |
boundedTest(3, Objects::nonNull); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I expected that
foo()
would reject thePredicate<Object>
on line 28, because the subject (an Integer) is not the same type that the predicate accepts (Object) . Instead, the compiler tried to find a type that would make the call valid, and so inferred thatS
must beObject
instead ofInteger
.I notice two things:
Given that each signature accepts these parameters, what practical differences are there between the signatures?
Is there a pair of inputs that one of these signatures accepts, but another rejects?
If the signatures accept the same parameters, in what situations would it matter that the compiler infers different types for S (and C)? I suspect that if these methods were overloaded, the different type inferences might affect overload resolution. I haven't explored that yet.