Pattern Matching is one of the most powerful and most widely used feature in Scala. Scala’s Pattern Matching is often compared to Java’s Switch construct, but the capabilities that Scala provides with Pattern Matching is more interesting and far better than traditional Switch. apply and unapply are two important concepts one needs to understand before deep diving into Pattern Matching.

Apply and Unapply

Scala lets one extend the function call syntax to values other than functions. Using the apply method of a companion object is a common Scala idiom for constructing objects. For example, consider a Person class and it’s companion object

class Person(val name: String, val age: Int) object Person {

def apply(name: String, age: Int): Person = new Person(name, age)

}

Then one can create an object without calling the new keyword.

val john = Person("John", 28)

Internally, it is calling the apply method of Person companion object to create new Person object.

val john = Person.apply("John", 28)

The unapply method can be treated as the opposite of the apply method of a companion object. An apply method takes construction parameters and turns them into an object, whereas the unapply method takes an object and extracts values from it, usually the values from which the object was constructed. unapply method always return an Option type, it returns either Some[T] (if it could successfully extract the parameter from the given object) or None , which means that the parameters could not be extracted.

Extending the Person companion object to implement unapply

object Person {

def apply(name: String, age: Int): Person = new Person(name, age)



def unapply(person: Person): Option[(String, Int)] = {

if (person.age == 0) None

else Some((person.name, person.age))

}

}

Now, we can extract out name and age from the Person object like this

val Person(name, age) = john println(s"Hi, my name is $name and I am $age years old!")

Any object which implements the unapply method is called as Extractor and they are widely used in Pattern matching. Extractors provides a way to extract something from a type you have no control over or if one needs additional ways of pattern matching against a certain data.

Case Class vs Class

A case class in Scala, by default implements these apply and unapply methods. Therefore, one can refactor the Person class to a case class

case class Person(name: String, age: Int)



val john = Person("John", 28)



val Person(name, age) = john



println(s"Hi, my name is $name and I am $age years old!")

A Better Switch

Scala’s match construct looks very similar to switch construct used in Java or C++.

def toYesOrNo(choice: Int): String = choice match {

case 1 => "Yes"

case 0 => "No"

case _ => "Meh"

}

It can also be used to assert types, instead of using isInstanceOf operator

obj match {

case x: Int => x

case s: String => Integer.parseInt(s)

case _: BigInt => Int.MaxValue

case _ => 0

}

It can be extended to add a Guard clause to a pattern

obj match {

case x: Int if x > 25 => "Greater than 25"

case x: Int if x <= 25 => "Lesser than or equal to 25"

case _ => "Meh"

}

Since case class defines unapply method,

trait Tree

case object Leaf extends Tree

case class Node(elm: String, left: Tree, right: Tree) extends Tree // ::: operator of list is used to prefix list.

def inOrder(node: Tree): List[String] = {

node match {

case Node(e, Leaf, Leaf) => List(e)

case Node(e, l, Leaf) => inOrder(l) ::: List(e)

case Node(e, Leaf, r) => List(e) ::: inOrder(r)

case Node(e, l, r) => inOrder(l) ::: List(e) ::: inOrder(r)

}

}