Trouble with wildcards

Paul Sandoz paul.sandoz at oracle.com
Mon Dec 16 06:42:43 PST 2013


Hi Remi,

Reducing it down a little:

import java.util.*;
import java.util.function.*;

class A {

  static class X {};
  static class Y extends X {};

  public static void main(String[] args) {
    Predicate<X> px = x -> x instanceof X;
    Predicate<Y> py = y -> y instanceof Y;

    Predicate<? super Y> psy = px;

    Predicate<? super Y> superyandy = psy.and(py);    // <-- error
    superyandy.test(new Y());
  }
}

$ javac -Xdiags:verbose A.java
A.java:15: error: method and in interface Predicate<T> cannot be applied to given types;
  Predicate<? super Y> superyandy = psy.and(py);    // <-- error
                                       ^
  required: Predicate<? super CAP#1>
  found: Predicate<Y>
  reason: argument mismatch; Predicate<Y> cannot be converted to Predicate<? super CAP#1>
  where T is a type-variable:
    T extends Object declared in interface Predicate
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object super: Y from capture of ? super Y
1 error


It's confusing...

Paul.

On Dec 14, 2013, at 7:43 PM, Remi Forax <forax at univ-mlv.fr> wrote:

> Hi all,
> I've tried to explain in code how a Stream (here a Flow to avoid 
> confusion) can be implemented (just filter/map, only a sequential 
> stream) with consecutive operations, filter.filter or map.map optimized.
> 
> I end up with the code below which compiles but if instead of
>   return Flow.this.filter(/*predicate.and(predicate2)*/ t -> 
> predicate.test(t) && predicate2.test(t));
> I replace it by
>   return Flow.this.filter(predicate.and(predicate2));
> the compiler refuses to compile and I don't understand why :(
> 
> Here predicate is a Predicate<? super T>, so predicate2 should be a 
> Predicate<? super ? super T>,
> because and() is declared like this: Predicate<T>.and(Predicate<? super T>)
> predicate2 is a Predicate<? super T> so it should match Predicate<? 
> super ? super T> but
> it doesn't.
> 
> Is it a bug in the compiler or in my head ?
> 
> cheers,
> Rémi
> 
> @FunctionalInterface
> public interface Flow<T> {
>   public void forEach(Consumer<? super T> consumer);
> 
>   public default Flow<T> filter(Predicate<? super T> predicate) {
>     return new Flow<T>() {
>       @Override
>       public void forEach(Consumer<? super T> consumer) {
>         Flow.this.forEach(u -> {
>           if (predicate.test(u)) {
>             consumer.accept(u);
>           }
>         });
>       }
>       @Override
>       public Flow<T> filter(Predicate<? super T> predicate2) {
>         return Flow.this.filter(/*predicate.and(predicate2)*/ t -> 
> predicate.test(t) && predicate2.test(t));
>       }
>     };
>   }
> 
>   public default <R> Flow<R> map(Function<? super T, ? extends R> 
> function) {
>     return new Flow<R>() {
>       @Override
>       public void forEach(Consumer<? super R> consumer) {
>         Flow.this.forEach(t -> consumer.accept(function.apply(t)));
>       }
>       @Override
>       public <U> Flow<U> map(Function<? super R, ? extends U> function2) {
>         return Flow.this.map(function.andThen(function2));
>       }
>     };
>   }
> 
>   public static <T> Flow<T> create(Iterable<? extends T> iterable) {
>     return iterable::forEach;
>   }
> 
>   public static void main(String[] args) {
>     List<Integer> list = IntStream.range(0, 
> 10).boxed().collect(Collectors.toList());
>     Flow<Integer> flow = create(list);
>     flow.filter(x -> x != 5).filter(x -> x != 
> 2).forEach(System.out::println);
>     flow.map(x -> x * 2).map(x -> x + 1).forEach(System.out::println);
>     flow.filter(x -> x != 5).map(x -> x * 2).filter(x -> x != 2).map(x 
> -> x / 2).forEach(System.out::println);
>   }
> }
> 



More information about the lambda-dev mailing list