Skip to content

Instantly share code, notes, and snippets.

@dhemery
Created April 21, 2019 17:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhemery/6296673e08df382d58351da2aeb71e25 to your computer and use it in GitHub Desktop.
Save dhemery/6296673e08df382d58351da2aeb71e25 to your computer and use it in GitHub Desktop.
Effects of Different Ways of Expressing Type Dependence in Generic Methods
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);
}
}
@dhemery
Copy link
Author

dhemery commented Apr 21, 2019

I expected that foo() would reject the Predicate<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 that S must be Object instead of Integer.

I notice two things:

  1. Each method signature accepts parameters I've passed.
  2. When the type of the subject and the type of the predicate's input differ, the compiler infers different types for S (and C) for different signatures.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment