incompatible types compile error
Arul Dhesiaseelan
aruld at acm.org
Tue Nov 20 11:05:47 PST 2012
Thanks Maurizio for the excellent writeup, this clears up many things for
me.
On Tue, Nov 20, 2012 at 2:51 AM, Maurizio Cimadamore <
maurizio.cimadamore at oracle.com> wrote:
> On 19/11/12 21:36, Arul Dhesiaseelan wrote:
>
> Thanks Maurizio for the clarification.
>
> For me, the first usage fails to compile as expected. The second usage
> works perfectly fine, I wonder what is different that make second example
> work without the type parameter. I tested with today's build.
>
> List<Album> sortedFavs1 = albums.stream()
> .filter(a -> a.tracks.stream().anyMatch(t -> (t.rating >= 4)))
> .sorted(comparing((Function<Album, Comparable>) album ->
> album.name))
> .into(new ArrayList<Album>());//java: incompatible types:
> java.util.stream.Stream.Destination cannot be converted to
> java.util.List<streams.Album>
>
> List<Album> sortedFavs2 = new ArrayList<Album>();
> albums.stream()
> .filter(a -> a.tracks.stream().anyMatch(t -> (t.rating >= 4)))
> .sorted(comparing((Function<Album, Comparable>) album ->
> album.name))
> .into(sortedFavs2);
>
>
> The difference between the two versions is that in the second one you are
> not assigning the results of 'into' to anything - unlike the first case -
> that is, the compiler doesn't detect the incompatibility because there's no
> incompatibility to detect!
>
> As for why the program fails - here's a quick reproducer we can reason
> about:
>
> import java.util.function.*;
> import java.util.*;
> import java.util.stream.*;
>
> import static java.util.Comparators.comparing;
>
> class Album { }
>
> class Test {
>
>
> void test(Stream<String> albums, List<String> d) {
> List<String> test1(Stream<String> s, Function<String, Comparable> f) {
> return s.sorted(comparing(f)).into(new ArrayList<String>());
> }
>
> List<String> test2(Stream<String> s, Function<String, Comparable> f,
> List<String> d) {
> return s.sorted(comparing(f)).into(d);
> }
> }
>
> Note that this doesn't even have lambdas in it - the fact that you were
> using a cast actually made the lambda pointless in terms of how
> inference/overload resolution work - i.e. when you have:
>
> (Function<String, Comparable>) <lambda>
>
> the type of the lambda WILL be Function<String, Comparable> - no matter
> what's the contents of the lambda.
>
> So, why does this give an unchecked warning in the first place?
>
> The signature of Comparator.comparing is:
>
> <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> mapper)
>
>
> So, in order to check method applicability we have to test as to whether
> Function<Album, Comparable> is a subtype of Function<? super T, ? extends
> U>, written
>
> Function<Album, Comparable> <: Function<? super T, ? extends U>
>
> Now, after subtyping, you end up with the following constraints on
> inference variables: T, U
>
> T <: Album
> U :> Comparable
>
> Since the first part of type-inference (15.12.2.7) takes lower bound into
> account, you end up with U inferred to Comparable.
> The next step is to check as to whether the inferred type conforms to the
> declared bound - to do that you have to replace the inferred type in the
> bound declaration and see whether the inferred type is a subtype of that
> replacement:
>
> Comparable <: [U:=Comparable]Comparable<? super U> = Comparable<? super
> Comparable>
>
> This is valid - but requires an unchecked conversion for going from
> Comparable (raw) to Comparable<? super Comparable> - hence, an unchecked
> conversion is required here.
>
> The spec mandates that whenever an unchecked conversion occurs within a
> method call, the signature of the method must be erased - this means that
> the Comparators.comparing method will simply return a raw 'Comparator'. So
> again, we are passing a raw type where a generic type is expected - again
> unchecked conversion kicks in and the return type of 'Stream.sorted' is
> erased leading to a raw 'Stream'. Now, accessing a member of a raw type
> ('into' in this case) always cause the signature of the method to be
> erased, which means the compiler will see that 'into' has the following
> signature:
>
> Destination into(Destination)
>
> So, it's absolutely fine to pass in any implementation of the Destination
> class (as ArrayList is) - but the problem is in the return type - which
> will only be (a raw) Destination. So, trying to assign the return type of a
> raw 'into' call to anithing but Destination will result in a type-mismatch.
>
> Maurizio
>
>
> Here is the working version with the type parameter.
>
> List<Album> sortedFavs = albums.stream()
> .filter(a -> a.tracks.stream().anyMatch(t -> (t.rating >= 4)))
> .sorted(comparing((Function<Album, String>) album -> album.name))
> .into(new ArrayList<Album>());
>
>
> - Arul
>
>
> On Mon, Nov 19, 2012 at 3:37 AM, Maurizio Cimadamore <
> maurizio.cimadamore at oracle.com> wrote:
>
>> The problem is that, since you are using Comparable (note the absence of
>> type-parameters) you are effectively triggering an uunchecked conversion
>> there - the result would be that the erased signature of 'into' will be
>> used instead - that is, the return type of into will be simply Destination
>> - not the type inferred from the argument - hence the incompatible types
>> error.
>>
>> Btw - I'm getting the error for both versions of the example you sent.
>>
>> Maurizio
>>
>>
>> On 16/11/12 23:01, Arul Dhesiaseelan wrote:
>>
>>> This works, btw.
>>>
>>> List<Album> sortedFavs = new ArrayList<Album>();
>>> albums.stream()
>>> .filter(a -> a.tracks.stream().anyMatch(t -> (t.rating >=
>>> 4)))
>>> .sorted(comparing((Mapper<Comparable, Album>) album ->
>>> album.name))
>>> .into(sortedFavs);
>>>
>>>
>>>
>>> On Fri, Nov 16, 2012 at 12:38 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>>>
>>> On 11/16/2012 10:57 PM, Arul Dhesiaseelan wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> I am trying to run a slightly modified version from the latest State of
>>>>>
>>>> the
>>>>
>>>>> Lambda libraries edition.
>>>>>
>>>>> List<Album> sortedFavs =
>>>>> albums.stream()
>>>>> .filter(a -> a.tracks.stream().anyMatch(t -> (t.rating >=
>>>>>
>>>> 4)))
>>>>
>>>>> .sorted(comparing((Mapper<Comparable, Album>) album ->
>>>>> album.name))
>>>>> .into(new ArrayList<Album>());
>>>>>
>>>>> java: incompatible types: java.util.stream.Stream.Destination cannot be
>>>>> converted to java.util.List<Album>
>>>>>
>>>>> Any idea what could be wrong here?
>>>>>
>>>> the signature of the method into.
>>>>
>>>> -Arul
>>>>>
>>>>> Rémi
>>>>
>>>>
>>>>
>>>>
>>
>
>
More information about the lambda-dev
mailing list