scalaupickle

How to use the ReadWriter for parameterized types


I am trying to migrate to the latest version of upickle 0.7.1. Where I had previously passed around implicit Readers and Writers I believe I must now use a single ReadWriter and explicitly define them in a companion object for any case classes I want to serialize. But I cannot figure out how this works for a parameterized type. So for example say I had the following before upgrading (from 0.4.4):

trait OldTrait[T] {

    implicit val evr: Reader[T]
    implicit val evw: Writer[T]

    def save(t: T): String = write(t)
    def restore(str: String): T = read[T](str)
}

class MyOldClass[T](implicit val evr: Reader[T], val evw: Writer[T]) extends OldTrait[T] {
}

case class Request[T](msg: T)

val c1 = new MyOldClass[Request[Int]]

The above code compiled fine for me. To migrate this code I have tried the following:

trait NewTrait[T] {
    implicit val evrw: ReadWriter[T]
}

class MyNewClass[T](implicit val evrw: ReadWriter[T]) extends NewTrait[T] {

}

object Request {
    implicit val rw: ReadWriter[Request[_]] = macroRW
}

val c2 = new MyNewClass[Request[Int]]

But this will not compile for me. I get the following errors:

Don't know how to derive type ...Request[] implicit val rw: ReadWriter[Request[]] = macroRW

... could not find implicit value for parameter evrw: upickle.default.ReadWriter[Request[Int]]

...not enough arguments for constructor MyNewClass: (implicit evrw: upickle.default.ReadWriter[Request[Int]])MyNewClass[Request[Int]]. Unspecified value parameter evrw. val c2 = new MyNewClass[Request[Int]]

What would be the correct approach to migrating the old code?


Solution

  • Not tested, but I would expect you need

    implicit def rw[T: ReadWriter]: ReadWriter[Request[T]] = macroRW
    

    So e.g. because there is a ReadWriter[Int], there's also a ReadWriter[Request[Int]].

    (I would be very surprised if this doesn't work, but you can certainly do it manually instead of macroRW in this case.)