Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get an ambiguity error in this code?

Tags:

java

Let's say we have these 3 classes:

class A { }
class B extends A { }

public class App {
    static void f(int i, A a) { }
    static void f(float j, B b) { }
   
    static public void main() {
        int i = 0;
        B b = new B();
        App.f(i, b);
    }
}

This produces the error:

App.java:11: error: reference to f is ambiguous
        App.f(i, b);
           ^
  both method f(int,A) in App and method f(float,B) in App match
1 error

Why does it not choose the type f(int, A) since i is an integer?

like image 828
Rafik Bouloudene Avatar asked Sep 06 '25 03:09

Rafik Bouloudene


1 Answers

It is ambiguous because of two reasons:

  • both overloads are applicable, and;
  • neither overload is more specific than the other

Notice that both the f(int, A) overload and the f(float, B) overload can be called with the parameters (i, b), since there is an implicit conversion from int to float, and an implicit conversion from B to A.

What happens when there are more than one applicable method? Java is supposed to choose the most specific method. This is described in §15.12.2.5 of the language spec. It turns out that it is not the case that one of these overloads are more specific than the other.

One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:

  • m2 is generic [...]

  • m2 is not generic, and m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ n, n = k).

  • m2 is not generic, and m1 and m2 are applicable by variable arity invocation [...]

Only the second point applies to the two overloads of f. For one of the overloads to be more specific than the other, every parameter type of one overload has to be more specific than the corresponding parameter type in the other overload.

A type S is more specific than a type T for any expression if S <: T (§4.10).

Note that"<:" is the subtyping relationship. B is clearly a subtype of A. float is actually a supertype (not subtype!) of int. This can be derived from the direct subtyping relations listed in §4.10.1. Therefore, neither of the overloads is more specific than the other.

The language spec goes on to talk about maximally specific methods, which doesn't really apply to f here. Finally, it says:

Otherwise, the method invocation is ambiguous, and a compile-time error occurs.

More Examples

static void f(int x) {}
static void f(float x) {}

when called with an int are not ambiguous because the int overload is more specific.

static void f(int x, B a) {}
static void f(float x, A a) {}

when called with argument types (int, A) are not ambiguous because the (int, B) overload is more specific.

static void f(int x, A a) {}
static void f(float x, A a) {}

when called with argument types(int, A) are not ambiguous because the (int, A) overload is more specific. Note that the subtyping relationship is reflexive (i.e. A is a subtype of A).

like image 172
Sweeper Avatar answered Sep 07 '25 21:09

Sweeper