0
votes

I need to provide type class instances for a bunch of case classes all derived from a single trait, but as far as I understand Scala compiler expects an instance for a specific class and doesn't go up the inheritance hierarchy. So this code:

trait Base

sealed trait Child extends Base

case class Concrete() extends Child

trait Printable[A] {
  def print(value: A): String
}

object WtfTrait {
  def print[A](x: A)(implicit ev: Printable[A]) = {
    println(ev.print(x))
  }

  implicit val printableBase = new Printable[Base] {
    override def print(value: Base): String = value.toString
  }

  val x = Concrete()
  print(x)
}

doesn't compile with an error reading could not find implicit value for parameter ev: Printable[Impl]. Is there a way to define a single type class instance for the base trait and avoid repitition maybe by using Shapeless or something.

2
Impl is not described in your codecchantep

2 Answers

3
votes

Guess you mean Printable[Concrete] (that's to say a Show typeclass instance).

Need to update to printableBase definition as bellow:

trait Base

sealed trait Child extends Base

case class Concrete() extends Child

trait Printable[A] {
  def print(value: A): String
}

object WtfTrait {
  def print[A](x: A)(implicit ev: Printable[A]) = {
    println(ev.print(x))
  }

  // HERE
  implicit def printableBase[T <: Base] = new Printable[T] {
    override def print(value: T): String = value.toString
  }

  val x = Concrete()
  print(x)
}
2
votes

Printable can be made contravariant by adding a - sign:

trait Printable[-A]

This makes Printable[X] a subtype of Printable[Y] if Y is a subtype of X. In particular, Printable[Base] is a subtype of Printable[Concrete] and can be used when the compiler looks for an implicit of that type.