Search code examples
scala

Understand how to use apply and unapply


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
}

Solution

  • 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

    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

    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)
    }