Bad interaction between wildcard and functional interface conversion

Gernot Neppert mcnepp02 at googlemail.com
Sun Jul 5 13:13:36 UTC 2015


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
>>
>





More information about the core-libs-dev mailing list