scalacontravarianceimplicits

Scala: Implicit resolution, ambigiuty and contravariance


I have the following piece of Scala with ambigiuous implicits, which I would have thought should work, due to lower priority given to inherited implicits. But it does not - it fails with an ambiguous implicit values-error. Can someone explain to me why priorities does not work here?

trait Printer[-T] {
  def prettify(instance:T): String
}

trait LowPriorityPrinter {
  implicit val anyPrinter:Printer[Any] = new Printer[Any]{ def prettify(instance:Any) = instance.toString() }
}

object Printer extends LowPriorityPrinter {
  implicit val intPrinter = new Printer[Int]{ def prettify(instance:Int) = instance.toString() }
}

object MyApp extends App {

  def prettyprint[T](i:T)(implicit p:Printer[T]) = println(p.prettify(i))
  prettyprint(234)

}

Solution

  • The issue is simple, but nasty. The LowPriorityPrinter catch all instance of your type class needs to be generic, not for Any:

    object Printer {
      implicit val intPrinter:    Printer[Int] =
        new Printer[T]{ def prettify(x: T) = x.toString() + " (int") }
      implicit def anyPrinter[T]: Printer[T] =
        new Printer[T]{ def prettify(x: T) = x.toString() + " (general) }
    }
    

    Basically, the literal 234 is just as much an Int as it as an Any and neither of those types is more specific than the other (so the priority trick is useless).