ambiguous type inference while working with primitives
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu May 10 03:16:41 PDT 2012
On 10/05/12 05:14, Paulo Silveira wrote:
> I do have problems with even simpler cases (build 1.8.0-jdk8-b35-20120502):
>
> List<Object> list = new ArrayList<>();
> list.sort(Comparators.comparing(Object::toString));
> list.sort(Comparators.comparing((o) -> o.toString()));
>
> both examples fail compiling:
>
> error: no suitable method found for comparing(member reference)
> list.sorted(Comparators.comparing(Object::toString));
> ^
> method Comparators.<T#1>comparing(DoubleMapper<T#1>) is not applicable
> (cyclic inference - cannot infer target type for given
> lambda/method reference expression)
> method Comparators.<T#2>comparing(LongMapper<T#2>) is not applicable
> (cyclic inference - cannot infer target type for given
> lambda/method reference expression)
> method Comparators.<T#3>comparing(IntMapper<T#3>) is not applicable
> (cyclic inference - cannot infer target type for given
> lambda/method reference expression)
> method Comparators.<T#4,U>comparing(Mapper<T#4,U>) is not applicable
> (cyclic inference - cannot infer target type for given
> lambda/method reference expression)
> where T#1,T#2,T#3,T#4,U are type-variables:
> T#1 extends Object declared in method<T#1>comparing(DoubleMapper<T#1>)
> T#2 extends Object declared in method<T#2>comparing(LongMapper<T#2>)
> T#3 extends Object declared in method<T#3>comparing(IntMapper<T#3>)
> T#4 extends Object declared in method<T#4,U>comparing(Mapper<T#4,U>)
> U extends Comparable<? super U> declared in method
> <T#4,U>comparing(Mapper<T#4,U>)
>
> It does not work even if I try to split the statement:
>
> Comparator<Object> c = Comparators.comparing(Object::toString);
>
> The only way to make it work is to be explicit:
>
> list.sort(Comparators.<Object, String>comparing(Object::toString));
This is a known problem - if the method accepts only one parameter you
are kinda stuck in an inference cycle - in order to infer the method
signature you'd need info from the lambda parameter types, but since
those types are implicit (same applies for method references), the
compiler needs to look at the method signature to understand how to
type-check the lambda.
We are exploring some solutions in order to mitigate this problem.
>
> Going further, couldn't we have an List.sort overload to directly
> receive a Mapper as parameter?
>
> public<U extends Comparable<? super U>> void sort(Mapper<T, U>
> mapper) default {
> Collections.sort(this, new MapperComparator<T, U>(mapper));
> }
>
> This would make possible to invoke a quite short list.sort(Class::getAttribute);
I'll leave this to our library gurus ;-)
Maurizio
>
>
> --
> Paulo Silveira
> Caelum | Ensino e Inovação
> www.caelum.com.br
>
>
> 2012/5/9 Jim Gish<jim.gish at oracle.com>:
>> 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
>>
>>
>>
>>
More information about the lambda-dev
mailing list