Ambiguous reference

Vicente-Arturo Romero-Zaldivar vicente.romero at oracle.com
Fri Nov 15 05:54:49 PST 2013


On 13/11/13 18:59, Zhong Yu wrote:
> Here's my understanding how the process works.
>
> When javac sees
>
>      forEach( v->... )
>
> two pieces of information of the implicit lambda are used to prune
> overloading methods:
> 1. the arity. therefore BiConsumer/BiPredicate are excluded
> 2. whether the lambda body returns void or a real type.
Hi,

Overloading methods are discriminated by arity, return types are 
considered in a later phase once you know what methods to consider. This 
was implemented for several reasons, simplification between them, but 
also has some drawbacks.

So in all cases the compiler output is correct.

Thanks,
Vicente

>
> If the lambda body is a block, it's quite clear whether it's void or
> not. It seems to me that this would work:
>
>      public void forEach(BiConsumer<? super Integer, ? super T> biConsumer) {
>          forEach((v) -> { biConsumer.accept(1, v); });
>      }
>      public void forEach(BiPredicate<? super Integer, ? super T> biPredicate) {
>          forEach(v -> { return biPredicate.test(1, v); } );
>      }
>
> ( ... But it fails in javac build 115. javac bug?)
>
> If the lambda body is a "statement expression", like in your original example
>
>      public void forEach(BiConsumer<? super Integer, ? super T> biConsumer) {
>          forEach((v) -> biConsumer.accept(1, v) );
>      }
>      public void forEach(BiPredicate<? super Integer, ? super T> biPredicate) {
>          forEach(v -> biPredicate.test(1, v) );
>      }
>
> It's unclear what the return type is, so javac cannot use the return
> type to prune. Note that even though `biConsumer.accept(1, v)`
> obviously returns void, javac does not know that, because the type of
> `v` is not known yet. And even though `biPredicate.test(1, v)`
> obviously returns boolean, it is compatible to a function type that
> expects void return.
>
> Now, for each invocation, we have two potentially applicable methods.
>
> The next step tries to prune methods by checking argument types
> against method parameter types. Unfortunately, implicit lambda
> expressions are too vague, so they are simply ignored in this step.
>
> Therefore both methods are considered applicable methods. The most
> specific method is sought after. However neither method is more
> specific than the other, therefore we see the error message of
> ambiguity.
>
> If you use explicit lambda expressions, javac is able to do more
> pruning, so this works:
>
>      public void forEach(BiConsumer<? super Integer, ? super T> biConsumer) {
>          forEach((T v) -> biConsumer.accept(1, v) );
>      }
>      public void forEach(BiPredicate<? super Integer, ? super T> biPredicate) {
>          forEach( (T v) -> biPredicate.test(1, v) );
>      }
>
> So if you have overloading methods like this
>
>      public void forEach(Consumer<? super T> consumer) {
>          // ...
>      }
>      public void forEach(Predicate<? super T> predicate) {
>          // ...
>      }
>
> client code often cannot use implicit lambda expressions as arguments;
> and experts have advised against this kind of overloading scheme (two
> functional interfaces with the same arity)
>
>
> Zhong Yu
>
> On Wed, Nov 13, 2013 at 8:01 AM, Dávid Karnok <akarnokd at gmail.com> wrote:
>> Hello,
>>
>> I'm rewriting a library and run into a strange ambiguity error reported by
>> javac in JDK 8 b115, Windows 7 x86:
>>
>> public class Bug<T> {
>>      public void forEach(Consumer<? super T> consumer) {
>>          // ...
>>      }
>>      public void forEach(BiConsumer<? super Integer, ? super T> consumer) {
>>          forEach((v) -> consumer.accept(1, v));
>>      }
>>      public void forEach(Predicate<? super T> stoppableConsumer) {
>>          // ...
>>      }
>>      public void forEach(BiPredicate<? super Integer, ? super T>
>> stoppableConsumer) {
>>          forEach(v -> stoppableConsumer.test(1, v));
>>      }
>> }
>>
>> error: reference to forEach is ambiguous
>>          forEach((v) -> consumer.accept(1, v));
>>    both method forEach(Consumer<? super T>) in Bug and method
>> forEach(Predicate<? super T>) in Bug match
>>    where T is a type-variable:
>>      T extends Object declared in class Bug
>>
>> error: reference to forEach is ambiguous
>>          forEach(v -> stoppableConsumer.test(1, v));
>>    both method forEach(Consumer<? super T>) in Bug and method
>> forEach(Predicate<? super T>) in Bug match
>>    where T is a type-variable:
>>      T extends Object declared in class Bug
>>
>> I'm using NetBeans 7.4 (Build 201310111528) which doesn't report this
>> ambiguity in the editor, and the "highlight occurrences" correctly selects
>> the 3rd method when I select the forEach in the 4th method. However, the
>> clean and build fails with the errors above. I have to add explicit cast to
>> the problematic places.
>>
>> So I'm a bit confused right now. Is it a bug with NetBeans' editor, with
>> javac or simply the artifact of how overload resolution works?
>> --
>> Best regards,
>> David Karnok
>>



More information about the lambda-dev mailing list