ambiguous type inference while working with primitives
Jim Gish
jim.gish at oracle.com
Fri May 11 07:54:26 PDT 2012
On 05/10/2012 11:09 AM, Brian Goetz wrote:
> A few comments on this:
>
> 1. I think we have a solution in the works for the ambiguity problem
> you ran into, but it is not yet implemented. So, stay tuned.
>
> 2. The fused operations mapReduce may go away. These fused ops exist
> only as a workaround for the pain of reducing over unnecessarily boxed
> values (think: mapReduce(String::length, Integer::plus)). The library
> can fuse map/reduce even without a fused method, so this is entirely
> about boxing. When we figure out the primitives story, this methods
> may or may not go away.
>
> 3. To answer your question: if you want to force a particular
> overload resolution, cast one or more lambda to the appropriate SAM
> type, such as
>
> mapReduce( (DoubleMapper) ..., (DoubleBinaryOperator) ...)
>
> On 5/9/2012 3:39 PM, Jim Gish wrote:
>> On 03/06/2012 06:44 PM, maurizio cimadamore wrote:
>>> Hi
>>> This error occurs because you have two applicable methods, namely:
>>>
>>> *) comparing(IntMapper)
>>>
>>> *) comparing(LongMapper)
>>>
>>> When there are multiple applicable methods, the compiler tries to
>>> disambiguate the call-site using a routine called most-specific. The
>>> goal is to look at the two ambiguous signatures and see if one can be
>>> considered 'more specific' than the other. For instance, if you have
>>> two
>>> applicable methods, one accepting an Object, and the other accepting an
>>> Integer, the latter would 'win' as Integer is a subtype of Object.
>>>
>>> What's happening in this case is that the compiler doesn't have enough
>>> information to disambiguate the call-site by just looking at the method
>>> signatures - that's because IntMapper and LongMapper are two unrelated
>>> types, so the compiler doesn't know which method to pick - hence the
>>> ambiguity error.
>>>
>>> We are currently exploring the design space, to see if we can allow
>>> some
>>> restricted form of structural subtyping in the most specific algorithm
>>> (this would allow, i.e. to prefer IntMapper to LongMapper because the
>>> return type of the IntMapper's descriptor is more specific).
>>>
>>> Maurizio
>>>
>>> On 06-Mar-12 8:51 PM, Antoras wrote:
>>>> I get compiler errors due to ambiguous Mapper-objects. I have a class
>>>> Person which has a method getAge(). If the return value of this method
>>>> is 'int' the following inline Mapper-object produces an error:
>>>>
>>>> Comparator<Person> c = comparing((Person p1) -> p1.getAge());
>>>>
>>>> If the return type is 'Integer' the above code works.
>>>>
>>>> This line:
>>>>
>>>> Comparator<Person> c = comparing(Person::getAge);
>>>>
>>>> works neither with 'Integer' nor with 'int';
>>>>
>>>> Is this expected behavior or should the type checker recognize that
>>>> IntMapper is the first one to "choose"?
>>>>
>>>>
>>>> The error message:
>>>>
>>>> ListTest.java:203: error: reference to comparing is ambiguous, both
>>>> method<T#1>comparing(LongMapper<T#1>) in Comparators and method
>>>> <T#2>comparing(IntMapper<T#2>) in Comparators match
>>>> Comparator<Person> c = comparing((Person p1) ->
>>>> p1.getAge());
>>>> ^
>>>> where T#1,T#2 are type-variables:
>>>> T#1 extends Object declared in
>>>> method<T#1>comparing(LongMapper<T#1>)
>>>> T#2 extends Object declared in
>>>> method<T#2>comparing(IntMapper<T#2>)
>>>>
>>>
>> I think I have the same problem here:
>>
>> StringJoinerTest.java:46: error: reference to mapReduce is
>> ambiguous, both method mapReduce(LongMapper<? super
>> T>,long,LongBinaryOperator) in Iterable and method
>> mapReduce(DoubleMapper<? super T>,double,DoubleBinaryOperator) in
>> Iterable match
>> int altCompOfStringsLength = lastNames.mapReduce( e ->
>> e.length(), 0, (a, b) -> a+b);
>> ^
>> where T is a type-variable:
>> T extends Object declared in interface Iterable
>> 1 error
>>
>> So, how does one go about disambiguating this, other than breaking out
>> the lambda expressions (and somewhat defeating the point of the
>> compactness value). This, for example, works:
>>
>> int stringsLength = lastNames.map(e -> e.length()).reduce(0,
>> (a, b) -> a+b);
>>
>> Thanks,
>> Jim
>>
>>
>>
>>
Maurizio's fix solved my problem. (Thanks for the quick fix
Maruizio!). I thought I tried the casting and was getting a different
compile error. I'll have to go back and check.
More information about the lambda-dev
mailing list