incompatible types compile error

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Nov 20 04:51:58 PST 2012


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 <http://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 <http://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 <http://album.name>))
>         .into(new ArrayList<Album>());
>
>
> - Arul
>
>
> On Mon, Nov 19, 2012 at 3:37 AM, Maurizio Cimadamore 
> <maurizio.cimadamore at oracle.com 
> <mailto: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 <http://album.name>))
>                      .into(sortedFavs);
>
>
>
>         On Fri, Nov 16, 2012 at 12:38 PM, Remi Forax
>         <forax at univ-mlv.fr <mailto: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 <http://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