Scala gives us the sealed keyword, which allows the compiler to check at compile time that all cases of a type have been handled with So the compiler checks in compile-time - yes. - compile-time -that you handled all the cases.
Why is this insanely useful(IMO - the biggest advantages of scala over a lot of languages): let's take an example: When you write a calculator
Sealed trait Expression {
case class Add(left:Int,right:Int) extends Expression
case class SimpleValue(num:Int) extends Expression
}
And now you write your sum function
def sum(exp:Expression):Int = exp match {
case Add(left,right) => left+right
case SimpleValue(value) => value
}
And everything is right in the world.
Now a year later, a new developer comes to the picture, and adds a third instance, let's say Multiply.
case class Multiply(left:Int,right:Int)
And now he compiles the code. If you wrote your code properly, the sum function will break and the compiler will tell you, hey buddy, you need to handle the division here. And then
def sum(exp:Expression):Int = exp match {
case Add(left,right) => left+right
case Multiply(left,right) => left*right
case SimpleValue(value) => value
}
And all is great. Now imagine, you would have added - (an un-needed - default value there) for example
def sum(exp:Expression):Int = exp match {
case Add(left,right) => left+right
case SimpleValue(value) => value
case _ => 1
}
The compiler will automatically see that Multiply is handled by the 1 branch, and will not force you to go there and check it out. Now imagine this example, but when you have 1000 files. and this becomes a really really powerful weapon that helps us catch bugs in compile - time. So as a rule, we avoid avoid default value in pattern matching unless they are mandatory and on purpose. and they should be scarcely used them on sealed traits with compound logic.