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