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