Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type Class and Subclassing

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?

like image 856
Peter Schmitz Avatar asked Apr 09 '26 00:04

Peter Schmitz


1 Answers

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:

  • http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/
like image 75
Alois Cochard Avatar answered Apr 11 '26 21:04

Alois Cochard



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!