Overload resolution simplification
maurizio.cimadamore at oracle.com
Thu Aug 15 16:10:48 PDT 2013
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
>>>> 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
>>>> 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
>>>> 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
>>>> way. That means sticking with a design principle that guided us in the
>>>> - but I do understand that much of this stuff is subtle and hard to
>>> 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
>>>> 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 :-)
>> know what? People didn't even realized that when using them.
>>> Zhong Yu
More information about the lambda-spec-observers