Overload resolution simplification

maurizio cimadamore maurizio.cimadamore at oracle.com
Sat Aug 10 11:16:31 PDT 2013

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 
>> 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?

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 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