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