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 }
An extractor object is an object with an unapply method. Whereas the apply method is like a constructor which takes arguments and creates an object, the unapply takes an object and tries to give back the arguments. This is most often used in pattern matching and partial functions.
In Scala, every object that has an unapply() method is called an extractor object. The unapply() method is the basis of pattern matching in Scala because this method helps us to extract data values compacted in objects.
Pattern matching is a mechanism for checking a value against a pattern. A successful match can also deconstruct a value into its constituent parts. It is a more powerful version of the switch statement in Java and it can likewise be used in place of a series of if/else statements.
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) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With