Overload resolution simplification

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

On Sat, Aug 10, 2013 at 1:16 PM, maurizio cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> On 10-Aug-13 7:09 PM, Zhong Yu wrote:
>> On Sat, Aug 10, 2013 at 12:41 PM, maurizio cimadamore
>> <maurizio.cimadamore at oracle.com> wrote:
>>> On 10-Aug-13 5:50 PM, Zhong Yu wrote:
>>>> I'd appreciate that very much! The map() overloading use case wouldn't
>>>> be rare in practice. People will feel bad if javac cannot see that the
>>>> lambda parameter type is obviously fixed.
>>> While I'm sympathetic with this position, this would mean that stuff like
>>> IntStream map(IntFunction<T>)
>>> <Z> Stream<Z> map(Function<T, Z>)
>>> map(x->1);
>>> would work, while the following 'static' variant:
>>> <U> IntStream map(Stream<U> s, IntFunction<U>)
>>> <U, V> Stream<V> map(Stream<U>, Function<U, V>)
>>> Stream<String> ss = ...
>>> map(ss, x->1);
>>> Would _not_ work. And it feels a bit weird - if the first case is deemed
>>> important, the second is equally important - it's just same example in a
>>> different style.
>> Probably not equally important in practice. We've seen quite a few
>> uses cases of the 1st form, but not of the 2nd.
>> Will it do more harm to allow 1st and disallow 2nd, because of the
>> confusion it causes? I think not.
>> The people affected are mostly API designers, not API users. They are
>> fewer in number, and presumably more knowledgeable. If they are
>> surprised that the 2nd form of overload doesn't work well, that is
>> bad, but not as bad as depriving them of the 1st form of overload.
> I don't think anybody can have a clear idea of what code we'll 2-3 years
> down the road. If we stick to the cases we've seen so far, then one could
> argue that what we have (simplfied version) is also good enough, given that
> we had to change _zero_ code in our library/tests (which relied heavily on
> implicit lambdas/inference etc.). If we want to be future proof, that's ok
> too - but being half-future proof I don't understand.
>>> Then I guess next step would be to say - obviously javac can see what 'U'
>>> is
>>> by looking at the input stream. Which is essentially where we were: in
>>> this
>>> case instantiating U is fine but there are cases (Comparators.comparing)
>>> where it's not ok. And it seems like not everybody is comfortable in
>>> making
>>> those subtle distinctions.
>>> It's obviously a problem of 'where to draw the line'. But there are
>>> advantages in scaling back a bit and give up a bit of expressiveness as
>>> the
>>> model you get is much simpler to explain and so are its boundaries. This
>>> property is not to be underestimated.
>>> Note that the 'same parameter' rule you are advocating for requires
>>> global
>>> reasoning: to see whether a lambda can be type-checked you have to
>>> consider
>>> all matching signatures and see if they impose same parameter on the
>>> implicit lambda. This can be trivial to see in simple examples (such as
>>> map)
>>> - but what if the example is more convoluted? I.e. many overloads? Or
>>> different sam types using different ordering for type parameters i.e.
>>> Function1<X, Y> {
>>>     Y apply(X x)
>>> }
>>> Function2<X, Y> {
>>>     X apply(Y x)
>>> }
>> I don't understand this one, can you give an example?
> With the above declarations you can have:
> m(Function1<String, Integer> f1)
> m(Function2<String, Integer> f2)
> m(x->...) //are both methods forcing same parameter on the lambda?

This example is not fair; a single non-overloaded m(Function2) is
confusing by itself.

> Of course this is not 'hard' to see - but it's yet another step you'll have
> to do mentally when reasoning as to whether an implicit lambda would be ok
> or not. If you put together wildcards (which have special treatment in SAM
> conversion), nested SAM types and type-variable substitution, I believe that
> you can get easily to examples in which it's very hard to see whether two
> methods will end up enforcing same constraints on a given (nested?) lambda.

I'm sure that it's easy for us outsiders to just say "move the line a
little", while the "line" is actually something multi dimensional,
convoluted and blurry.

> Maurizio
>>> I believe that in such cases (or even more complex ones with nested SAM
>>> types as type-parameters) we'll be essentially at compiler's mercy - i.e.
>>> it
>>> would be very hard to judge whether a method call would succeed w/o
>>> trying
>>> it first on javac. And that's bad too.
>> I agree, but Java has passed that point. Most programmers have trouble
>> dealing with generics.
>>> Maurizio

More information about the lambda-spec-observers mailing list