This is because this type witness is also a function. It is declared in Predef
as:
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
So A <:< JsValue
is also a function (A) => JsValue
. You might wonder what the function does: it does nothing, it takes an A
and directly returns it (as a JsValue
).
To see why this is useful consider this example:
sealed trait Root { def bip() { println("bip") } }
def makeBip[A <: Root](a: A) {
a.bip() // works because a is known to the type system to be a Root
}
def makeBip2[A](a: A)(implicit ev: A <:< Root) {
a.bip() // works, because implicit resolution turns it into `ev(a).bip()`
}
The last method makeBip2
would not compile without the implicit because even though you know that a
is a Root
thanks to the evidence, the type system doesn't. You could cast it, it would be sure to work:
def makeBip3[A](a: A)(implicit ev: A <:< Root) {
a.asInstanceOf[Root].bip() // ugly
}
But this doesn't feel right. If only you had a way you convert a
to a Root
... but wait, you do: the evidence itself!
def makeBip4[A](a: A)(implicit ev: A <:< Root) {
ev(a).bip() // works!
}
And since implicit parameters are available as implicits within the method, a.bip()
will be automatically converted to ev(a).bip()
and you never need to know a function was involved.
However, the type system only uses the implicit to resolve an A
into a JsValue
, but not a Seq[A]
into a Seq[JsValue]
or a Reads[A]
into a Reads[JsValue]
.
So in you case, this.map(witness)
just makes the type system understand that a Reads[A]
is a Reads[JsValue]
by applying that function that does nothing, so that it can be composed with something that takes a JsValue
and returns a B
.
See the Generalized type constraits question on SO for more.