eprst
eprst

Reputation: 753

Scala: implicits, subclassing and member types

Lets say we want to use type classes 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 we want to print are:

trait Foo {
    type K
    val k: K
}

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

cool. Now I want to build 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 check that implicits are resolved:

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, lets 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's the problem with the first approach? Unfortunately we're on 2.10, and second solution still doesn't work. It compiles until we add one more sime printer like

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

and it mysteriously breaks Printer[IntFoo] implicit:

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

compiler bugs?

Upvotes: 3

Views: 151

Answers (1)

Rado Buransky
Rado Buransky

Reputation: 3294

Order of implicit declarations matters. In your source code reorder original code from

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

to

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

Upvotes: 2

Related Questions