Hi Remi,

I think it's fair to say that I know my share of Java Generics, so I generally understand the motivation of introducing wildcards into method signatures. Just in your particular case (and in your original example), I don't see what you gain by having the "super" wildcard for the outer Consumer's type parameter.
If you leave it out, the code compiles without problems:

static <K, T> Function<K, T> factory(Consumer<BiConsumer<? super K, ? super T>> consumer, Function<? super K, ? extends T> ifAbsent) {
...
}

Can you enlighten me?

Cheers, Gernot

Am 29.06.2015 15:49, schrieb Remi Forax:
Bitten again by the very same issue :(

The following code doesn't compile:
static <K, T> Function<K, T> factory(Consumer<? super BiConsumer<? super K, ? super T>> consumer, Function<? super K, ? extends T> ifAbsent) {
    HashMap<K, T> map = new HashMap<>();
    consumer.accept(map::put);
    return key -> map.computeIfAbsent(key, ifAbsent);
  }

I really think that it's a serious bug, the only workaround is to not use wildcards correctly, i.e. <K, T> Function<K, T> factory(Consumer<BiConsumer<? super K, ? super T>> consumer, Function<? super K, ? extends T> ifAbsent)

cheers,
Rémi

On 05/27/2015 05:29 PM, Remi Forax wrote:
Hi all,

The way the conversion between a lambda (or a method reference) and a functional interface is specified doesn't take wildcard (exactly ? super) into account making the concept of contravariance of functional interface less intuitive that it should be.

The following code compiles:
  private static void create(Consumer<Consumer<String>> consumer) {
    consumer.accept(s -> System.out.println(s));
  }

This one doesn't compile because "? super Consumer<? super String>" is not a functional interface: private static void create2(Consumer<? super Consumer<? super String>> consumer) {
    consumer.accept(s -> System.out.println(s));
  }

The workaround is to introduce a cast :(
private static void create3(Consumer<? super Consumer<? super String>> consumer) {
    consumer.accept((Consumer<String>)s -> System.out.println(s));
  }
which is stupid in this case because there is no ambiguity.
This cast is just here because the JLS doesn't consider that ? super Consumer<...> is a valid target type

IMO, this bug is very similar to JDK-6964923 and i think the spec should be changed to allow ? super Foo to be a valid target type for a lambda conversion (obviously if Foo is a functional interface).

regards,
Rémi




Reply via email to