V remove(final Object key); // from java.util.Map
V remove(final long key); // from it.unimi.dsi.fastutil.longs.Long2ObjectFunction
Unfortunately I’m not able to call remove because Scala thinks the first one takes Any (not AnyRef), the second takes long, which is also an Any, and so I get the error,
Error:(94, 15) ambiguous reference to overloaded definition,
both method remove in trait Long2ObjectMap of type (x$1: Any)V
and method remove in trait Long2ObjectFunction of type (x$1: Long)V
match argument types (Long)
builder.remove(x)
Is there a way to tell Scala to use the method that takes long? I can add : Any to my parameter to get it to use the (Object) one, but that’s not ideal. : Long doesn’t help.
The ones that compile for remove(long) in the above tree are,
val m: Long2ObjectOpenHashMap[V] = ...
m.remove(3L)
val m: Long2ObjectFunction[V] = ...
m.remove(3L)
val m: AbstractLong2ObjectFunction[V] = ...
m.remove(3L)
For some reason, Long2ObjectMap, and AbstractLong2ObjectMap do not compile. Based on that, I would expect that Long2ObjectOpenHashMap to not compile, but it does.
This isn’t specific to Any and AnyVal like it appeared. It applies to any overloaded defs where the type of the argument to one is the parent of the other, and you call the method taking the child on a class where the method taking the parent is overridden.
class X
class Y extends X
class Parent {
def f(x: X): Unit = ???
def f(x: Y): Unit = ???
}
class ChildOverridesX extends Parent {
override def f(x: X): Unit = ???
}
class ChildOverridesY extends Parent {
override def f(x: Y): Unit = ???
}
object Usage {
// compiles
(null: Parent).f(new Y)
// does not compile
(null: ChildOverridesX).f(new Y)
// compiles
(null: ChildOverridesY).f(new Y)
}
Based on the som-snytt’s response quoted here you can workaround this problem overriding both methods.
… Scala says you can reason about an overloaded f without referring to the application itself, the use site. Given an overloaded f, it scores the two fs for which is “more specific.” That means taking a more specific parameter, or being defined in a subclass. Usually, subclassing means imposing more specific constraints. If the two fs score the same, then you can’t choose between them, so the overload is ambiguous.
class ChildOverridesAny extends Parent {
override def f(x: Any): Unit = println("override any")
override def f(x: Long): Unit = super.f(x)
}
object Usage {
// compiles
(new ChildOverridesAny).f(3L)
(new ChildOverridesAny).f("foo")
}