Why there is ambiguous reference to overloaded definition in this code?
class A {
def m(a1: A, o2: Any): A = {
print("1")
a1
}
def m(a1: A, a2: A): A = {
print("2")
a1
}
def m(o1: Any, o2: Any): Any = {
print("3")
o1
}
def m(o: Any): Any = {
print("4")
o
}
}
class B extends A {
def m(b1: B, o2: Any): A = {
print("5")
b1
}
override def m(a: A, o2: Any): B = {
print("6")
this
}
override def m(o1: Any, o2: Any): Any = {
print("7")
o1
}
def m(i: Int): Unit = { print("8") }
}
val a = new A
val b = new B
b.m(a, a)
The code above gives compile error:
ambiguous reference to overloaded definition,
[error] both method m in class B of type (a: A, o2: Any)B
[error] and method m in class A of type (a1: A, a2: A)A [error] match argument types (A, B)
But my understanding is that method m in class A of type (a1: A, a2: A)A
is more specific
than method m in class B of type (a: A, o2: Any)B
Any hints are appreciated.
You are exactly right - the version of m
in A
is more specific and that is actually the problem.
Since you are actually invoking m
on an instance of b
(ie. b.m(a, a)
) the compiler first checks that there is a method that matches the signature in B
. Since B
does indeed have a method that passes type checking (ie. m(a: A, o2: Any): B
) so far so good. But whilst the compiler also checks the superclass A
it finds a more specific version of m
(ie. m(a1: A, a2: A): A
).
The problem is you invoked m
on an instance of B
but you are explicitly asking the compiler to find a method that takes two arguments of type A
. The compiler is now unsure of which version you actually intended to get executed hence the compilation error.
A better compilation message might be:
"Hey I found a version of m
further up the hierarchy in A
that better meets your requirements but I see you are explicitly invoking m
on a B
(not an A
) so I don't really know which one to choose now - you better check this otherwise if I just choose one you may not get the results you were after at runtime."