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