I'm trying to get a better understanding of the correct usage of apply
and unapply
methods.
Considering an object that we want to serialize and deserialize, is this a correct usage (i.e. the Scala way) of using apply
and unapply
?
case class Foo
object Foo {
apply(json: JValue): Foo = json.extract[Foo]
unapply(f: Foo): JValue = //process to json
}
Firstly, apply
and unapply
are not necessarily opposites of each other. Indeed, if you define one on a class/object, you don't have to define the other.
apply
is probably the easier to explain. Essentially, when you treat your object like a function, apply is the method that is called, so, Scala turns:
obj(a, b, c)
to obj.apply(a, b, c)
.
unapply
is a bit more complicated. It is used in Scala's pattern matching mechanism and its most common use I've seen is in Extractor Objects.
For example, here's a toy extractor object:
object Foo {
def unapply(x : Int) : Option[String] =
if(x == 0) Some("Hello, World") else None
}
So now, if you use this is in a pattern match like so:
myInt match {
case Foo(str) => println(str)
}
Let's suppose myInt = 0
. Then what happens? In this case Foo.unapply(0)
gets called, and as you can see, will return Some("Hello, World")
. The contents of the Option
will get assigned to str
so in the end, the above pattern match will print out "Hello, world".
But what if myInt = 1
? Then Foo.unapply(1)
returns None
so the corresponding expression for that pattern does not get called.
In the case of assignments, like val Foo(str) = x
this is syntactic sugar for:
val str : String = Foo.unapply(x) match {
case Some(s) => s
case None => throw new scala.MatchError(x)
}