Exact/inexact method reference difference

John Spicer jhs at edg.com
Mon Oct 6 13:22:38 UTC 2014


I'm forwarding this question from a member of our development team.

Thanks,

John.

Take this example:

 @FunctionalInterface interface I1 { void f(Integer i); }
 @FunctionalInterface interface I2 { void f(String s); }
 class Y {
   void m1(Integer i) {}
   void m2(Integer... i) {}
 }
 class X {
   void g(I1 i) {}
   void g(I2 i) {}
   void f(Y y) {
     g(y::m1);   // Okay (exact method reference)
     g(y::m2);   // Ambiguous (inexact method reference)
   }
 }

What in the JLS is causing this difference?

According to 15.12.2.1, when determining the list of "potentially applicable" methods for the method invocation(s) of g, one must consider whether there is "at least one potentially applicable method" for the method reference to be "potentially compatible".  

The first question is: according to the JLS, are both I1 and I2 "potentially compatible" with Y::m1 and Y::m2?  If so, then in both the g(y::m1) and g(y::m2) method invocation cases, there will be two "potentially applicable" methods.  15.12.2.1 seems like it might benefit from some clarification in this area:

- 15.12.2.1 was originally written for method invocations and talks about arguments to method invocations.  15.13.1 refers to 15.12.2.1 for the method reference case, and in that case, there are no arguments.

- 15.12.2.1 lists the conditions for an expression to be "potentially compatible" with a target type, but that seems only relevant for poly expressions yet the term "potentially compatible" seems to be used for all expressions.

Once the set of potentially applicable methods has been chosen, the inexact method reference is deemed not "pertinent to applicability" (15.12.2.2), so we end up with an ambiguous method invocation (which matches javac's behavior), but what about the exact method reference case?  As part of 15.12.2.2, y::m1 is tested to see if it "is compatible in a strict invocation context" with both I1 and I2.  That leads to 15.13.2, but that section doesn't seem to differentiate at all based on the parameters of I1::f and I2::f and their compatibility with Y::m1.  Hence the second question: what states that I1::f is compatible with Y::m1 and I2::f isn't?



More information about the compiler-dev mailing list