I'm using the Play framework's JSON library, which uses a type class to implement the Json.toJson
function. (I may decide to use another technique with less static typing, like reflection; but for now I want to use this library because it's helping me learn the Scala type system.)
I have a bunch of simple case classes that need to be passed to toJson
, so I have to implement an implicit Writes[T]
object for each of them. A first cut might look like this, for each of the classes.
// An example class
case class Foo(title: String, lines: List[String])
// Make 'Foo' a member of the 'Writes' typeclass
implicit object FooWrites extends Writes[Foo] {
def writes(f: Foo) : JsValue = {
val fields = Seq("title" -> toJson(f.title),
"lines" -> toJson(f.lines))
JsObject(fields)
}
}
Each class will have a similar implicit value, so I could abstract the common part, as below. But this doesn't compile, because I'm not sure how to declare the type.
def makeSimpleWrites[C](fields: (String, C => T??)*) : Writes[C] = {
new Writes[C] {
def writes(c: C) : JsValue = {
val jsFields = fields map { case (name, get) => (name, toJson(get(c)))}
JsObject(jsFields)
}
}
}
implicit val fooWrites : Writes[Foo] =
makeSimpleWrites[Foo]("title" -> {_.title}, "lines" -> {_.lines})
implicit val otherWrites ...
The issue is the type T
that I want to pass to makeSimpleWrites
. It can't be a normal type parameter because that T is different for each item in fields
. Is this an existential type? I have yet to use one of these. Flailing at syntax...
def makeSimpleWrites[C](fields: (String, C=>T forSome { type T; implicit Writes[T] })*)
Is this possible in Scala? If so, what is the syntax?