Exhaustivity Checking

One of the really cool things about Scala that helps you write more reliable code is a nifty compiler feature called Exhaustivity checking. In a nutshell it's the compilers way of letting you know if you forgot to check for any possible polymorphic permutations when you're doing pattern matching.

Take this sealed trait Operation and it's concrete implementations as
an example:

sealed trait Operation  
case class Addition(left: Int, right: Int) extends Operation  
case class Subtraction(left: Int, right: Int) extends Operation  
case class Division(left: Int, right: Int) extends Operation  
case class Multiplication(left: Int, right: Int) extends Operation  

Making Operation a sealed trait means that any class that wants to extend it must be declared within the same file, preventing any implementations of Operation to exist anywhere else.

So the moment the compiler does a first pass over the file containing the sealed trait, it knows every possible implementation of that sealed trait. In this case the only possible implementations of Operation are Addition, Subtraction, Division, and Multiplication.

Just like most other abstract and case class implementations in scala we can perform pattern matching on Operation as expected:

val operation: Operation = Addition(1, 3)  
val result = operation match {  
  case Addition(left, right)       => left + right
  case Subtraction(left, right)    => left - right
  case Division(left, right)       => left / right
  case Multiplication(left, right) => left * right
}

Now where things start to get interesting is when we forget to implement the case clause for one implementation of Operation in the pattern matching statement:

val operation: Operation = Addition(1, 3)  
val result = operation match {  
  case Addition(left, right)       => left + right
  case Division(left, right)       => left / right
  case Multiplication(left, right) => left * right
}

The previous code produces the following compiler warning:

adt.scala:11: warning: match may not be exhaustive.  
It would fail on the following input: Subtraction(_, _)  
    val result    = operation match {

How cool is that! The compiler is letting us know that we forgot to add a specific implementation of Operation to the pattern matching statement and it's telling us the implications this has!