heads-up: biggie overload rewrite

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Jul 25 09:47:45 PDT 2013


Dear lambdians,
I've just pushed a patch [1] that enhances javac overload 
resolution/most specific story in several ways. One of the most notable 
effects is the removal of the dreaded 'inference loop' message [2]. The 
logic behind that message was noble: at the time we thought it would 
have been better to report an error when the compiler was forced to 
infer a variable to some 'default' instantiation (such as j.l.Object), 
as this could cause severe downstream problems when type-checking a 
lambda whose body depended on that choice. However, this was before we 
added the more complex inference support; now that we have a more 
capable inference engine, with all bells and whistles, we also have a 
bigger degree of complexity and, because inference constraints are 
propagated transitively, the line between default and non-default 
instantiation has become a lot fuzzier than it used to be. Hence the 
decision of getting rid of that logic (and related error message) - 
which also makes the language more consistent (as inference typically 
only gave such errors when lambdas/method references are present).

Other improvements in sight for the structural most specific logic; many 
of you [3,4,5] have reported cases in which the compiler was unable to 
distinguish between several signatures, where the 'right' choice seemed 
indeed really easy. The problem in that case was that the structural 
most specific check would only kick in if the compiler can prove that 
all target types agree on the parameter types to be inferred for i.e. an 
implicit lambda. In certain cases (when generic methods were used), the 
compiler couldn't do that, so it basically went back to the old most 
specific logic. Here's an example:

<T,R> Stream<R> map(Stream<T> s, Function<T,R> f) { }
<T> IntStream map(Stream<T> s, ToIntFunction<T> f) { }

map(ss, s->s.length()); //now ok - used to be ambiguous

There are rules to this game though; if the variable to be inferred to 
be able to type-check the lambda (T in the above example) happened to 
depend on one of the inference variables mentioned in the method return 
type, the most specific check would fail and the compiler would again 
report an ambiguity. The reason for this is that it's not possible to 
guarantee that the eager instantiation of T would remain the same after 
looking at the target type (and we want overload selection to be 
independent from the target type, as we believe it's crucial to keep the 
model tractable for developers).

The last improvement is related to the way in which method arguments are 
type-checked; javac is now able to reason about the subtle dependencies 
that arise when a lambda is passed as an argument to a generic method; 
in the above case for instance, javac will detect that there's a 
dependency between T and R in the first method. In fact, if we had an 
instantiation for T, we would then be able to type-check the lambda and 
we will most likely be able to derive new constraints for R. So, it 
would be mad for the compiler to go and try to infer R _before_ looking 
at the lambda expression.

I think those improvements go a long way in terms of polishing the 
overall overload resolution story that the language presents to 
developers; it gets rid of several outstanding issues, and makes the 
whole overload selection process more streamlined and consistent. I'm 
looking forward to hear your feedback (and bug reports :-)) as you start 
using the next promoted lambda bits.

Enjoy the ride!

[1] - http://hg.openjdk.java.net/lambda/lambda/langtools/rev/d34073d069c8
[2] - 
http://mail.openjdk.java.net/pipermail/lambda-dev/2013-July/010352.html
[3] - 
http://mail.openjdk.java.net/pipermail/lambda-dev/2013-July/010476.html
[4] - 
http://mail.openjdk.java.net/pipermail/lambda-dev/2013-June/010088.html
[5] - 
http://mail.openjdk.java.net/pipermail/lambda-dev/2013-July/010590.html

Maurizio











More information about the lambda-dev mailing list