Overload issue - more-specific-ness

Zhong Yu zhong.j.yu at gmail.com
Fri Mar 14 20:41:30 UTC 2014


On Fri, Mar 14, 2014 at 12:48 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
> Yes, this is correct behavior.  The rule is that overloading methods whose
> arguments are same-arity SAMs (and where other arguments can't be used to
> disambiguate) are going to lead to ambiguities.

In my example the arity is 0, therefore the lambda expression is
"explicit"; such overloading should be fine, according to our previous
discussions.

I agree that in general overloading should be avoided, it is too
complicated for everybody. However I have a legitimate case here.
Suppose I name the two methods differently

    void fooA(Runnable r){}
    void fooB(Callable<List<?>> c){}

the meaning of fooA and fooB are closely related, and it is easy for
the programmer to make the mistake of invoking fooA while fooB is
actually intended

    fooA( ()->new ArrayList<Void>() ); // compiles!

Even more sinisterly, say fooA(mref) was initially passed a
void-returning method reference, and later the method is refactored to
return List<?> -- fooA(mref) still passes javac silently.

That is too dangerous. It's safer to overload the methods, and let
javac choose the more "appropriate" method for the programmer. (The
issue  reported in top post does not block me from doing so, I don't
have to have the subtype relationship.)

Zhong Yu

>
> Bad: overloaded methods with functional interfaces of the same arity in the
> same position
>
> <T,U> void foo(Function<T,U>)
> <T> void foo(ToIntFunction<T>)
>
> Unless another non-functional argument can provide disambiguation
>
> <T,U> void foo(String, Function<T,U>)
> <T> void foo(int, ToIntFunction<T>)
>
> OK: overload with the same functional interface in the same position
> <T,U> void foo(Function<T,U>, String)
> <T,U> void foo(Function<T,U>, int)
>
>
>
>
>
>
> On 3/14/2014 4:10 AM, Peter Levart wrote:
>>
>>
>> On 03/14/2014 12:48 AM, Zhong Yu wrote:
>>>
>>> Consider this program:
>>>
>>>      // like Runnable, but throws
>>>      interface RunnableX extends Callable<Void>
>>>      {
>>>          void run() throws Exception;
>>>
>>>          default Void call() throws Exception
>>>          {
>>>              run();
>>>              return null;
>>>          }
>>>      }
>>>
>>>      static void foo(RunnableX r){}
>>>      static void foo(Callable<List<?>> c){}
>>>
>>> The overload should be fine, because both functional interfaces are
>>> 0-arg. And foo#2 should be more specific than foo#1.
>>>
>>> However the following program fails to compile
>>>
>>>      public void test()
>>>      {
>>>          foo( ()->new ArrayList<Void>() );
>>>          // javac: reference to foo is ambiguous
>>>          // both method foo(RunnableX) and method
>>> foo(Callable<List<?>>) match
>>>      }
>>>
>>> Is it the correct behavior or a bug? It seems to me that foo#2 should
>>> be the most-specific method here.
>>>
>>> ( If RunnableX does NOT extend Callable<Void>, the program compiles.)
>>
>>
>> ...and selects foo(Callable). So when interfaces are not related the
>> structural type of Callable is prefered to that of RunnableX. If
>> RunnableX is related to (a subtype of) Callable then most specific rule
>> should prevail. I think. But it seems that structural fitness and
>> subtype specificness have equal weight here, so compiler is undecided.
>>
>> Regards, Peter
>>
>>>
>>> Thanks,
>>> Zhong Yu
>>>
>>
>>
>


More information about the lambda-dev mailing list