Overload resolution simplification
Zhong Yu
zhong.j.yu at gmail.com
Fri Aug 16 09:32:55 PDT 2013
On Fri, Aug 16, 2013 at 4:55 AM, Maurizio Cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> 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.
That problem exists before lambda.
This works:
List<String> list = Collections.emptyList();
This doesn't work:
void foo( List<String> list){ ... }
foo( Collections.emptyList() );
I'm not sure it's a good idea to remove a working case to achieve consistency.
Assigning an expression to a variable is much more explicit w.r.t.
context than passing it as a method argument, it's understandable that
the two cases are treated differently.
Zhong Yu
>
> Maurizio
>
>>
>>
>>
>> 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