potential compatibility and generic methods
Dan Smith
daniel.smith at oracle.com
Tue May 6 18:16:20 UTC 2014
Thanks for noticing the discrepancy. This is a javac bug. Your interpretation of 15.12.2.1 is correct. (This analysis is designed to be simple -- in particular, independent of types and substitution.)
I've reported the bug here: https://bugs.openjdk.java.net/browse/JDK-8042508
—Dan
On May 5, 2014, at 5:50 PM, Rafkind, Jon <jon.rafkind at hp.com> wrote:
> 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