I’m a bit confused about groovys method overloading behavior: Given the class
and tests below, I am pretty okay with testAStringNull and testBStringNull
throwing ambiguous method call exceptions, but why is that not the case for
testANull and testBNull then?
And, much more importantly: why does testBNull(null)
call String foo(A arg)? I guess the object doesn’t know about the type of the variable it’s bound to, but why is that call not ambiguous to groovy while the others are?
(I hope I explained well enough, my head hurts from generating this minimal
example.)
class Foo {
static class A {}
static class B {}
String foo(A arg) { return 'a' }
String foo(String s, A a) { return 'a' }
String foo(B arg) { return 'b' }
String foo(String s, B b) { return 'b' }
}
Tests:
import org.junit.Test
import Foo.A
import Foo.B
class FooTest {
Foo foo = new Foo()
@Test
void testA() {
A a = new A()
assert foo.foo(a) == 'a'
}
@Test
void testAString() {
A a = new A()
assert foo.foo('foo', a) == 'a'
}
@Test()
void testANull() {
A a = null
assert foo.foo(a) == 'a'
}
@Test
void testAStringNull() {
A a = null
assert foo.foo('foo', a) == 'a'
}
@Test
void testB() {
B b = new B()
assert foo.foo(b) == 'b'
}
@Test
void testBString() {
B b = new B()
assert foo.foo('foo', b) == 'b'
}
@Test
void testBNull() {
B b = null
assert foo.foo(b) == 'b'
}
@Test
void testBStringNull() {
B b = null
assert foo.foo('foo', b) == 'b'
}
}
It’s a (somewhat little-known) oddity of Groovy’s multi-dispatch mechanism, which as attempting to invoke the “most appropriate” method, in combination with the fact that the provided static type (in your case A or B) is not used as part of the dispatch mechanism. When you declare A a = null, what you get is not a null reference of type A, but a reference to NullObject.
Ultimately, to safely handle possibly null parameters to overloaded methods, the caller must cast the argument, as in
This discussion on “Groovy Isn’t A Superset of Java” may shed some light on the issue.