Overload resolution simplification

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Fri Aug 16 02:55:35 PDT 2013

On 16/08/13 00:26, Zhong Yu wrote:
> I had APIs that depended on last week's javac; they won't work after
> the simplification. See my previous posts for my use cases.
> Also I wish assignment context could be considered in the
>      Comparator<String> cs = Comparators.comparing(s ->expr);
> case (with overloaded comparing method). This use case seems rather
> common (brought up by multiple users on lambda-dev list).
Yeah - but I think it would be bad if that worked and this would not:

SomeTarget s = m(Comparators.comparing(s ->expr))

After all, comparing is a combinator and I expect such things to be 
passed around quite often to other APIs.

> On Thu, Aug 15, 2013 at 6:10 PM, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> wrote:
>> On 16/08/13 00:08, Zhong Yu wrote:
>>> On Thu, Aug 15, 2013 at 4:56 PM, Maurizio Cimadamore
>>> <maurizio.cimadamore at oracle.com> wrote:
>>>> On 15/08/13 22:36, Zhong Yu wrote:
>>>>> On Thu, Aug 15, 2013 at 9:00 AM, Maurizio Cimadamore
>>>>> <maurizio.cimadamore at oracle.com> wrote:
>>>>>> On 15/08/13 14:24, Zhong Yu wrote:
>>>>>>> That is not a reason for Java to reject it too. Java traditionally
>>>>>>> does inference based on assignment context; it'll be nice to continue
>>>>>>> to do that even with lambda arguments.
>>>>>> Well - that wasn't the point of my email; several posts in this thread
>>>>>> were
>>>>>> of the kind - 'why can't you guys just do what C# does' ?
>>>>>> I only tried to show that there are similar limitations elsewhere.
>>>>>> I explained at least 3-4 times as to why it is actually a good design
>>>>>> choice
>>>>>> not to allow stuff as Comparator.comparing overload - but somehow the
>>>>>> message doesn't get across. It's not like we are making something
>>>>>> dumber
>>>>>> or
>>>>>> different from what it used to be; it's true Java does inference based
>>>>>> on
>>>>>> target context - but that inference has _never_ affected the outcome of
>>>>>> overload resolution - which helps overload selection to remain
>>>>>> tractable
>>>>>> (i.e. not NP-hard, to go along with Eric Lippert). We'd like to keep it
>>>>>> that
>>>>>> way. That means sticking with a design principle that guided us in the
>>>>>> past
>>>>>> - but I do understand that much of this stuff is subtle and hard to
>>>>>> disgest.
>>>>>> Maurizio
>>>>> I've been only arguing for the limited overload case where all
>>>>> overloaded methods must agree upon the parameter types of implicit
>>>>> lambda arguments. That is a tractable strategy. In your previous
>>>>> example.
>>>>>> m(x->g(y->f(...)))
>>>>>> where m, g, f are overloads.
>>>>> if m,g,f satisfy the requirement about lambda parameter types, it is
>>>>> as tractable as
>>>>>      m( (X x)->g( (Y y)->f(...) ) )
>>>>> If m,g,f don't satisfy the requirement, fail immediately.
>>>>> Your other objection is that lambda parameter types may depend on
>>>>> method type variables; but it seems to me that we can first infer
>>>>> method type variables from other arguments and assignment target,
>>>>> after which the lambda parameter types are resolved per method,
>>>>> therefore we can check whether all methods agree upon lambda parameter
>>>>> types. This is done before selecting the most specific method.
>>>> In the complex cases (such as Comparator.comparing) this is almost always
>>>> the case; the lambda parameter type depends on some method type variable.
>>>> Now, if the method type-variable is in a position that doesn't overlap
>>>> with
>>>> the return type, fine, we could do that (in fact that's how javac worked
>>>> until last week).
>>>> If there's an overlap between the return type and that method
>>>> type-variable,
>>>> then you have two choices:
>>>> *) you throw the context into the overload machinery - thus making the
>>>> problem much harder - i.e. in cases like
>>>> m(g(x-> ...)) [see below]
>>>> *) you throw the context or give up depending on what kind of context is
>>>> -
>>>> i.e. if assignment context then it's ok [see below]
>>>> *) you give up (what javac did)
>>>> So, to stress the point I'm making - in a case like this:
>>>> SomeTarget s = g(x-> ...)
>>>> you have only one target to consider when you do overload selection of g.
>>>> In
>>>> this case, however:
>>>> m(g(x-> ...))
>>>> You have multiple targets to throw into the overload selection for g -
>>>> one
>>>> for each m overload. This means overload resolution grows exponentially
>>>> with
>>>> the level of nesting.
>>> Yes, I'm not saying this example should work.
>> Ok - so I believe you are saying you were ok with where javac was last week
>> (before simplification), right?
>>>>> This process may be too complex for programmers to follow, which is
>>>>> probably Dan's original point. I don't think people care. Nobody reads
>>>>> the 40 page long JLS section 15.12, yet people are doing ok based on
>>>>> intuition. I believe people's intuition can handle the limited
>>>>> overload capability too; in all examples shown so far, none is
>>>>> difficult to understand if the method is overloaded and the compiler
>>>>> accepts the invocation. It is more difficult to understand why
>>>>> overloading does not work in these cases.
>>>> The problem is that people (not necessarily users) is gonna need to read
>>>> that JLS section - as they will have to implement IDEs or different
>>>> compilers. Do we want _all_ compilers in the world to sign up for that
>>>> kind
>>>> of combinatorial explosion? AFAIK none of the IDEs out there (but
>>>> Netbeans,
>>>> which uses javac itself as a backend) implements the full
>>>> overload/inference
>>>> check as described in the spec and as was implemented in javac - and you
>>> hey, even javac doesn't "implements the full overload/inference check
>>> as described in the spec" :)
>> Heh - not this week - but last week yes :-)
>> Maurizio
>>>> know what? People didn't even realized that when using them.
>>>> Maurizio
>>>>> Zhong Yu

More information about the lambda-spec-observers mailing list