Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: implicits, subclassing and member types

Tags:

scala

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?

like image 430
eprst Avatar asked Jan 29 '26 03:01

eprst


1 Answers

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 ...
like image 56
Rado Buransky Avatar answered Jan 31 '26 17:01

Rado Buransky



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!