Overload resolution simplification

Zhong Yu zhong.j.yu at gmail.com
Sat Aug 10 11:23:20 PDT 2013


On Sat, Aug 10, 2013 at 1:07 PM, maurizio cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> On 10-Aug-13 6:35 PM, Zhong Yu wrote:
>>
>> On Sat, Aug 10, 2013 at 12:23 PM, maurizio cimadamore
>> <maurizio.cimadamore at oracle.com> wrote:
>>>
>>> On 10-Aug-13 4:30 PM, Michael Hixson wrote:
>>>>
>>>> On Sat, Aug 10, 2013 at 8:17 AM, maurizio cimadamore
>>>> <maurizio.cimadamore at oracle.com> wrote:
>>>>>
>>>>> On 10-Aug-13 3:41 PM, Michael Hixson wrote:
>>>>>>
>>>>>> I'm sure I sound like the most Comparator-obsessed guy in the world at
>>>>>> this point, but I have to ask...
>>>>>>
>>>>>> For a brief time, the Comparator.thenComparing methods had signatures
>>>>>> like
>>>>>> this:
>>>>>>
>>>>>>      <S extends T> Comparator<S> thenComparing(Comparator<? super S>
>>>>>> other);
>>>>>>
>>>>>> Those "narrowing type" changes were reverted for some reason, removing
>>>>>> the <S> type parameter.  Did it have to do with this topic -- the
>>>>>> ability of the compiler to interpret lambdas/method references in
>>>>>> overloaded methods?  Was that one of the "complex overload
>>>>>> disambiguation scenarios" that was abandoned?
>>>>>
>>>>> I believe so - the signature above has same problems as the 'comparing'
>>>>> one
>>>>> - the compiler can't do much with it, regardless the approach.
>>>>>
>>>>> Maurizio
>>>>>
>>>> That's precisely what I was getting at.  If the current situation is
>>>> no better than the one that led to removing the <S>, then why remove
>>>> the <S>?  I thought it was removed due to the compiler being unable to
>>>> infer <S> in lambdas and method references.  If we'll have to specify
>>>> types in those situations anyway, that explanation no longer makes
>>>> sense.
>>>
>>> I believe we are talking about two different methods - thenComparing used
>>> to
>>> be less problematic as it was changed (as you say) not be be a generic
>>> method, so that problems with stuck lambdas/overloaded method references
>>> were no longer biting. Since thenComparing is also not overloaded, I
>>> don't
>>
>> Maurizio, don't we have
>>
>>      thenComparing(T->U)
>>      thenComparing(T->int)
>> etc?
>
> You are right - was looking in the wrong place.
>
>>
>> If we cannot overload them, it'll be quite clumsy:
>>
>>      comparingInt(person::age).thenComparingDouble(person::height)
>>
>> looks like Hungarian notation:)
>
> Sure - but one bit of the hungarian notation (comparingInt) is unavoidable.
> And, I think it would be equally bad if half the API used overload and the
> other half used name mangling, based on some obscure compiler/language
> limitation.

Maybe people can do this:

    Comparator<Person> equality = (a,b)->0;

    equality.thenCompare(Person::age);


>
> Maurizio
>
>>
>>
>> Zhong Yu
>>
>>
>>> see any problem in using this method with the simplified approach too.
>>>
>>> Maurizio
>>>
>>>> I could be entirely off-base here.  If I'm mixing up issues, just tell
>>>> me
>>>> so.
>>>>
>>>> -Michael
>>>>
>>>>>> -Michael
>>>>>>
>>>>>> On Sat, Aug 10, 2013 at 6:56 AM, Maurizio Cimadamore
>>>>>> <maurizio.cimadamore at oracle.com> wrote:
>>>>>>>
>>>>>>> On 10/08/13 08:07, Andrey Breslav wrote:
>>>>>>>>
>>>>>>>> The case of overloaded method references worries me as well (lambdas
>>>>>>>> are
>>>>>>>> ok). Note that C# supports overloaded method references (method
>>>>>>>> groups)
>>>>>>>> as
>>>>>>>> arguments and only as arguments. It seems that inference can
>>>>>>>> disambiguate
>>>>>>>> method references rather well if we stick to what Dan proposes about
>>>>>>>> lambdas, because for a method reference there is no body to check.
>>>>>>>> But
>>>>>>>> maybe
>>>>>>>> I'm missing something.
>>>>>>>
>>>>>>> I believe C# is very different w.r.t. Java when it comes to
>>>>>>> target-typing
>>>>>>> and overload resolution - as such C# is not subject to all the issues
>>>>>>> we
>>>>>>> have here with 'stuck' expression - i.e. expression such as lambda
>>>>>>> and/or
>>>>>>> method references that cannot be looked at by the compiler because
>>>>>>> some
>>>>>>> type
>>>>>>> information is missing and the compiler cannot safely go ahead and
>>>>>>> instantiate the inference variable that would make it possible for
>>>>>>> the
>>>>>>> compiler to go ahead.
>>>>>>>
>>>>>>> I think 'comparing' is a good example of what can go wrong; even if
>>>>>>> we
>>>>>>> added
>>>>>>> support for overloaded method references (which we had last week),
>>>>>>> that
>>>>>>> API
>>>>>>> cannot be compiled by passing in a method reference, as the inference
>>>>>>> variable that is keeping the method reference stuck also appears on
>>>>>>> the
>>>>>>> 'comparing' return type. Which is, IMHO, a much more subtle
>>>>>>> explanation
>>>>>>> than
>>>>>>> 'just don't use an overloaded method reference here'.
>>>>>>>
>>>>>>> If we could have a scheme that worked in all cases, then I'd be
>>>>>>> totally
>>>>>>> in
>>>>>>> favor of having a more complex scheme. But, because of Java legacy, I
>>>>>>> don't
>>>>>>> think such an approach exists here.
>>>>>>>
>>>>>>> The only incremental improvement I see viable here, one that has been
>>>>>>> discussed before, would be to add some logic to detect that all
>>>>>>> overloaded
>>>>>>> methods force the same choice on the implicit lambda
>>>>>>> parameter/overloaded
>>>>>>> mref; that would be enough to get past Remi example - but it doesn't
>>>>>>> scale
>>>>>>> too well to generic methods.
>>>>>>>
>>>>>>> Maurizio
>>>>>>>
>>>>>>>
>>>>>>>>> On Aug 9, 2013, at 2:21 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>>>>>>>>>
>>>>>>>>>> Also I've a nice parsing framework that use type specialised
>>>>>>>>>> lambda
>>>>>>>>>> to
>>>>>>>>>> avoid boxing that doesn't compile anymore.
>>>>>>>>>>
>>>>>>>>>> public IntStream parse(BufferedReader reader,
>>>>>>>>>> ToIntFunction<String>
>>>>>>>>>> fun)
>>>>>>>>>> {  ... }
>>>>>>>>>> public LongStream parse(BufferedReader reader,
>>>>>>>>>> ToLongFunction<String>
>>>>>>>>>> fun) { ... }
>>>>>>>>>>
>>>>>>>>>> when called like this: parse(Integer::parseInt).
>>>>>>>>>
>>>>>>>>> Thanks for the use case.
>>>>>>>>>
>>>>>>>>> The 'parse' method is essentially the same shape as the 'map'
>>>>>>>>> method
>>>>>>>>> that
>>>>>>>>> was discussed by the EG quite a bit, with the eventual conclusion
>>>>>>>>> that
>>>>>>>>> it
>>>>>>>>> would be clearer to give each method a different name (parseInts,
>>>>>>>>> parseLongs, etc.).
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/2013-February/001417.html
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/2013-March/001441.html
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/2013-March/001458.html
>>>>>>>>>
>>>>>>>>> Doesn't mean that all other developers must follow our lead, but
>>>>>>>>> the
>>>>>>>>> fact
>>>>>>>>> that the EG tried it and then concluded that it didn't want
>>>>>>>>> overloading
>>>>>>>>> here
>>>>>>>>> is a strong argument that this is potentially a bad convention to
>>>>>>>>> follow.
>>>>>>>>>
>>>>>>>>> If somebody likes this convention anyway, then we made a
>>>>>>>>> special-case
>>>>>>>>> effort to support method references.  Unfortunately,
>>>>>>>>> Integer::parseInt
>>>>>>>>> is
>>>>>>>>> overloaded and so outside of the set of supported method
>>>>>>>>> references.
>>>>>>>>> As I
>>>>>>>>> mentioned in the EG meeting, by drawing the line like this, it's
>>>>>>>>> great
>>>>>>>>> when
>>>>>>>>> it works, and annoying when it doesn't and you fall off of a cliff.
>>>>>>>>> We
>>>>>>>>> considered using arity (e.g., "is this overloaded with arity 1?"),
>>>>>>>>> but
>>>>>>>>> that
>>>>>>>>> just moves the line, rather than solving the problem.
>>>>>>>>>
>>>>>>>>> So, I don't love the cliff, but I don't have a good alternative,
>>>>>>>>> other
>>>>>>>>> than just not having any special treatment at all.
>>>>>>>>>
>>>>>>>>> —Dan
>>>>>>>
>>>>>>>
>


More information about the lambda-spec-observers mailing list