Use the lowest subtype in a typeclass?

I have the following code:

sealed trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

trait Show[A] {
  def show(a: A): String

class Processor[A](a: A) {
  def print(implicit S: Show[A]): Unit = println(

implicit val showCat: Show[Cat] = c => s"Cat=${}"
implicit val showDog: Show[Dog] = d => s"Dog=${}"

val garfield = Cat("Garfield")
val odie = Dog("Odie")

val myPets = List(garfield, odie)

for (p <- myPets) {
  val processor = new Processor(p)
  processor.print // THIS FAILS AT THE MOMENT

Does anyone know of a nice way to get that line processor.print working?

I can think of 2 solutions:

  1. pattern match the p in the for loop.
  2. create an instance of Show[Animal] and pattern match it against all its subtypes.

But I'm wondering if there's a better way of doing this.

Thanks in advance!


  • Compile error is

    could not find implicit value for parameter S: Show[Product with Animal with]

    You can make Animal extend Product and Serializable

    sealed trait Animal extends Product with Serializable

    Also instead of defining implicit Show[Animal] manually

    implicit val showAnimal: Show[Animal] = {
      case x: Cat => implicitly[Show[Cat]].show(x)
      case x: Dog => implicitly[Show[Dog]].show(x)
      // ...

    you can derive Show for sealed traits (having instances for descendants) with macros

    def derive[A]: Show[A] = macro impl[A]
    def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
      import c.universe._
      val typA = weakTypeOf[A]
      val subclasses = typA.typeSymbol.asClass.knownDirectSubclasses
      val cases ={ subclass =>
        cq"x: $subclass => _root_.scala.Predef.implicitly[Show[$subclass]].show(x)"
        new Show[$typA] {
          def show(a: $typA): = a match {
            case ..$cases
    implicit val showAnimal: Show[Animal] = derive[Animal]

    or Shapeless

    implicit val showCnil: Show[CNil] = _.impossible
    implicit def showCcons[H, T <: Coproduct](implicit
      hShow: Show[H],
      tShow: Show[T]
    ): Show[H :+: T] = _.eliminate(,
    implicit def showGen[A, C <: Coproduct](implicit
      gen: Generic.Aux[A, C],
      show: Show[C]
    ): Show[A] = a =>

    or Magnolia

    object ShowDerivation {
      type Typeclass[T] = Show[T]
      def combine[T](ctx: CaseClass[Show, T]): Show[T] = null
      def dispatch[T](ctx: SealedTrait[Show, T]): Show[T] =
        value => ctx.dispatch(value) { sub =>

      implicit def gen[T]: Show[T] = macro Magnolia.gen[T]
    import ShowDerivation.gen

    or Scalaz-deriving

    sealed trait Animal extends Product with Serializable
    object Show {
      implicit val showDeriving: Deriving[Show] = new Decidablez[Show] {
        override def dividez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
          g: Z => Prod[A]
          ev: A PairedWith ShowA
        ): Show[Z] = null
        override def choosez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
          g: Z => Cop[A]
          ev: A PairedWith ShowA
        ): Show[Z] = z => {
          val x = g(z).zip(tcs)


    For cats.Show with Kittens you can write just

    implicit val showAnimal: Show[Animal] =

    The thing is that garfield and odie in List(garfield, odie) have the same type and it's Animal instead of Cat and Dog. If you don't want to define instance of type class for parent type you can use list-like structure preserving types of individual elements, HList garfield :: odie :: HNil.

    For comparison deriving type classes in Scala 3

    How to access parameter list of case class in a dotty macro