Why does the following code does not pick up the implicit val with the nearest supertype?
class A
class B extends A
trait TC[-T] { def show(t: T): String }
implicit val showA = new TC[A] { def show(a: A): String = "it's A" }
implicit val showB = new TC[B] { def show(b: B): String = "it's B" }
def doit[X](x: X)(implicit tc: TC[X]): Unit = println(tc.show(x))
doit(new A) // "it's A" as expected
doit(new B) // "it's A" ... why does this not give "it's B" ???
If you make TC
invariant (i.e., trait TC[T] (...)
), then it works fine and doit(new B)
returns "it's B" as expected.
By adding another implicit for type Any
, this issue is even extremer:
class A
class B extends A
trait TC[-T] { def show(t: T): String }
implicit val showA = new TC[A] { def show(a: A): String = "it's A" }
implicit val showB = new TC[B] { def show(b: B): String = "it's B" }
implicit val showAny = new TC[Any] { def show(x: Any): String = "it's Any" }
def doit[X](x: X)(implicit tc: TC[X]): Unit = println(tc.show(x))
doit(new A) // "it's Any" ... why does this not give "it's A" ???
doit(new B) // "it's Any" ... why does this not give "it's B" ???
And again it work's fine if TC
is invariant.
What's going on here, and how to solve it?
My goal is to have a contravariant TC
that implicitly chooses the nearest suitable supertype.