Suppose I have a type class:
trait ToString[T] {
def toString(t: T): String
}
And the following pimp:
implicit def ToStr[T: ToString](t: T) = new {
def toStr: String = implicitly[ToString[T]] toString t
}
Now let´s test it:
class A
implicit object AToString extends ToString[A] {
def toString(a: A) = "A"
}
(new A).toStr // A
Fine, so far. But if I introduce a subclass B of A:
class B extends A
(new B).toStr // could not find implicit value for evidence parameter of type ToString[B]
So I tried:
implicit def foo[X: ToString, Y <: X]: ToString[Y] = new ToString[Y] {
def toString(y: Y): String = implicitly[ToString[X]] toString y
}
But then I got:
(new B).toStr // diverging implicit expansion for type ToString[...]
What can I do to automatically use the type class for the superclass if there isn`t a type class for the subclass available?
You should make the type parameter of 'ToString' contravariant:
trait ToString[-T] {
def toString(t: T): String
}
implicit def ToStr[T: ToString](t: T) = new {
def toStr: String = implicitly[ToString[T]] toString t
}
class A
implicit object AToString extends ToString[A] {
def toString(a: A) = "A"
}
(new A).toStr // A
class B extends A
(new B).toStr // A
You can find some detailed information about variance in scala here:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With