Scala: implicits, subclasses and member types

Let's say we want to use typeclasses to implement pretty printing:

trait Printer[T] {def print(t: T)}

      

with default implementation for ints:

implicit object IntPrinter extends Printer[Int] {
    override def print(i : Int): Unit = println(i)
}

      

Our specific types that we want to print:

trait Foo {
    type K
    val k: K
}

class IntFoo extends Foo {
    override type K = Int
    override val k = 123
}

      

cool. Now I want to create printers for all Foos with printable Ks

implicit def fooPrinter[FP <: Foo](implicit ev: Printer[FP#K]): Printer[FP] =
    new Printer[FP] {
        override def print(f: FP): Unit = {
            Predef.print("Foo: ")
            ev.print(f.k)
        }
    }

      

lets you check that implicits are allowed:

def main(args: Array[String]) {
    implicitly[Printer[Int]]
    implicitly[Printer[IntFoo]]
}

      

scalac 2.11.2 says:

diverging implicit expansion for type Sandbox.Printer[Int]
    starting with method fooPrinter in object Sandbox
        implicitly[Printer[Int]]

      

whaat?

OK, let's rewrite fooPrinter:

implicit def fooPrinter[KP, FP <: Foo {type K = KP}](implicit ev: Printer[KP]) =
    new Printer[FP] {
        override def print(f: FP): Unit = {
            Predef.print("Foo: ")
            ev.print(f.k)
        }
    }

      

this works in 2.11, but what is the problem with the first approach? Unfortunately we're at 2.10 and the second solution still doesn't work. It compiles until we add another sime printer, for example

implicit object StringPrinter extends Printer[String] {
    override def print(s : String): Unit = println(s)
}

      

and it mysteriously breaks the printer [IntFoo] implicitly:

could not find implicit value for parameter e:   
    Sandbox.Printer[Sandbox.IntFoo]

      

compiler errors?

+3


source to share


1 answer


The order of implicit declarations applies. In the source code, reordering the source code from

implicit object IntPrinter ...
...
implicit def fooPrinter ...

      



to

implicit def fooPrinter ...
...
implicit object IntPrinter ...

      

+2


source







All Articles