heads-up: biggie overload rewrite

Sam Pullara spullara at gmail.com
Thu Jul 25 12:40:56 PDT 2013


Bummer. That is going to be surprising for people, especially with comparators.

Sam

On Jul 25, 2013, at 12:37 PM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:

> On 25/07/13 20:25, Maurizio Cimadamore wrote:
>> On 25/07/13 20:22, Maurizio Cimadamore wrote:
>>> On 25/07/13 19:15, Sam Pullara wrote:
>>>> I just did a build this morning and still see these fail:
>>>> 
>>>>           Comparator<String> comparator = Comparator.comparing(String::length);
>>>>           Comparator<String> comparator = Comparator.comparing(s -> s.length());
>>>> 
>>>> Are they still supposed to result in:
>>>> 
>>>> java: reference to comparing is ambiguous
>>>>     both method <T>comparing(java.util.function.ToLongFunction<? super T>) in java.util.Comparator and method <T>comparing(java.util.function.ToDoubleFunction<? super T>) in java.util.Comparator match
>>> Possible that you didn't pick up the changes?
>> The first work for me (haven't tried the second but should be ok).
> Sorry - was doing the wrong experiment; the first one WILL work - but not the second; the problem is that the signature:
> 
> public static <T> Comparator<T> comparing(ToIntFunction<? super T> keyExtractor) {
> 
> doesn't play by the rules illustrated in my email (T is included in the return type).
> 
> Maurizio
>> 
>> Maurizio
>>> Maurizio
>>>> Sam
>>>> 
>>>> On Jul 25, 2013, at 9:47 AM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
>>>> 
>>>>> 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