How to understand “case id ~ username => _” in anorm?
-
29-10-2019 - |
Question
Play2's anorm has a nice DSL of result parser:
case class User(id:Pk[String], name:String)
object User {
val parser = get[String]("id") ~ get[String]("name") map {
case id ~ name => User(id,name)
}
}
I don't understand this part case id ~ name
, why there can be a ~
between two variables?
I see case
normally as:
case id => _
case (a,b) => _
case Array(a, _*) => _
But I don't see case id ~ name
.
The source of ~
is here: https://github.com/playframework/Play20/blob/master/framework/src/anorm/src/main/scala/SqlParser.scala#L49
It defines a case class ~
:
case class ~[+A, +B](_1:A, _2:B)
And I write a simple test:
case class ~[+A, +B](_1:A, _2:B)
new ~("a","b") match {
case x ~ y => println(x , y)
}
It prints a,b
, but why the syntax is case x ~ y
?
Solution
You're already halfway there. It is possible because Scala lets you do that for all types that have been declared with two type parameters.
For example:
scala> case class Foo[X,Y]()
defined class Foo
scala> val x: Int Foo Double = Foo[Int,Double]()
x: Foo[Int,Double] = Foo()
While it may seem odd at first, it's actually a really nice property as this syntax can make things more readable. Consider the following example where a custom type for a tuple is defined:
class |::|[A, B](val left: A, val right: B)
object |::| {
def unapply[A, B](o: A |::| B) = Some((o.left, o.right))
}
Here, A |::| B
is used as infix notation for |::|[A, B]
. On the other hand, scala also allows infix notation for pattern matching (thanks to incrop for the reminder), as in case of the constructor in the following example:
new |::|("Hello","World") match {
case l |::| r => Console println (l + "," + r)
case _ =>
}