potential compatibility and generic methods
Rafkind, Jon
jon.rafkind at hp.com
Mon May 5 23:50:28 UTC 2014
Section 15.12.2.1 says method references are compatible with type variables when such a variable is a type parameter of the method. In the case that explicit type arguments are given, however, it seems the instantiation can be used to check compatibility, as in:
"A method reference (15.13) is potentially compatible with a functional interface type if, where the type's function type arity is n, there exists at least one potentially-applicable method for the method reference at arity n (15.13.1), and one of the following is true:"
In the following code, according to a strict interpretation of 15.12.2.1, makeRef#1 is potentially compatible.
==
public class x{
// makeRef#1
public static <T, U> void makeRef(U seed, BiFunction<U, ? super T, U> reducer, BinaryOperator<U> combiner) {}
// makeRef#2
// public static <T, R> void makeRef(Supplier<R> seedFactory, BiConsumer<R, ? super T> accumulator, BiConsumer<R,R> reducer){}
public <T> void test(){
x.<T, LinkedHashSet<T>>makeRef(LinkedHashSet::new, LinkedHashSet::add, LinkedHashSet::addAll);
}
}
==
makeRef#1 is compatible because 'U' is a type parameter and therefore LinkedHashSet::new is compatible due to the clause
"A lambda expression or a method reference is potentially compatible with a type variable if the type variable is a type parameter of the candidate method."
But if makeRef#1 was instantiated with the explicit type parameters given in the invocation then the compatibility check would be between LinkedHashSet<T> and LinkedHashSet::new, which fails because LinkedHashSet<T> is not a functional interface. javac gives an appropriate error message
==
$ javac x.java
x.java:17: error: method makeRef in class x cannot be applied to given types;
x.<T, LinkedHashSet<T>>makeRef(LinkedHashSet::new, LinkedHashSet::add, LinkedHashSet::addAll);
^
required: U,BiFunction<U,? super T,U>,BinaryOperator<U>
found: LinkedHashSet::new,LinkedHashSet::add,LinkedHash[...]ddAll
reason: argument mismatch; LinkedHashSet is not a functional interface
where U,T are type-variables:
U extends Object declared in method <T,U>makeRef(U,BiFunction<U,? super T,U>,BinaryOperator<U>)
T extends Object declared in method <T,U>makeRef(U,BiFunction<U,? super T,U>,BinaryOperator<U>)
1 error
==
So should 15.12.2.1 say something about instantiating the candidate method with the explicit type arguments before checking for potential compatibility?
The issue I run into is that, when makeRef#2 is uncommented, both makeRef#1 and makeRef#2 are potentially applicable but neither is more specific than the other so when makeRef#1 is chosen as the most specific method a compile error occurs.
--
More information about the lambda-spec-observers
mailing list