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