javagenericstype-inferencemethod-referencejls

Reduction procedure for MethodReference Expressions


Consider the following article from JLS that describes the reduction procedure for the MethodReference expressions during Type Inference process-:

A constraint formula of the form ‹MethodReference → T›, where T mentions at least one inference variable, is reduced as follows:

...

Otherwise, if the method reference is exact (§15.13.1), then let P1, ..., Pn be the parameter types of the function type of T, and let F1, ..., Fk be the parameter types of the potentially applicable method. The constraint reduces to a new set of constraints, as follows:

– In the special case where n = k+1, the parameter of type P1 is to act as the target reference of the invocation. The method reference expression necessarily has the form ReferenceType :: [TypeArguments] Identifier. The constraint reduces to ‹P1 <: ReferenceType› and, for all i (2 ≤ i ≤ n), ‹Pi → Fi-1›.

In all other cases, n = k, and the constraint reduces to, for all i (1 ≤ i ≤ n), ‹Pi → Fi›.

Here I would like to know some example cases on how the formation of the following are assumed and fitted in the clauses:

For example - below are my questions based on the interpretation:

FunctionType<P1,P2 ... Pn> funType = ClassCls::MethodRef;
...
class ClassCls {
...
 public static <F1, ..., Fk> RetType potentiallyApplicbMethod(...){}
}

Solution

  • Why will FunctionType have more number of arguments than the potentiallyApplicbMethod?

    There are different forms of method references. One of the forms is ReferenceType::InstanceMethod, or as the Java Tutorials call it, "reference to an instance method of an arbitrary object of a particular type".

    Example:

    public class Main {
    
        public static void main(String[] args) {
            // this is a "reference to an instance method of an arbitrary object of a particular type"
            BiConsumer<Main, String> bar = Main::foo;
        }
    
        private <T> void foo(T t) {
    
        }
    }
    

    Clearly, the function type of BiConsumer has 2 parameters, but foo only has one. The extra first parameter of the function type is needed because you need an instance to call foo, and we haven't specified that instance in the method reference Main::foo. bar.accept(new Main(), "foo") would be the same as calling new Main().foo("foo"). This is what the JLS meant by "target reference" - it's the object on which you call the method. It has nothing to do with return types.

    Now you should also be able to see why the JLS says that the method reference in the n=k+1 case must be of the form ReferenceType :: [TypeArguments] Identifier, as opposed to, say, Primary :: [TypeArguments] Identifier.

    for the case when n=k I assume this is given as when all types specified in FunctionType matches exactly with all the types specified for potentiallyApplicbMethod?

    No, this case just refers to the other kinds of method references: