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