Use ADTs to implement enumerations

When you need to implement an enumeration, use an ADT, not Enumeration.


Enumeration suffers from a major flaw: exhaustivity is not checked in pattern matches.

For example:

object Status extends Enumeration {
  val Ok, Nok = Value

def foo(w: Status.Value): Unit = w match {
  case Status.Ok => println("ok")

This compiles without a warning but will blow up at runtime:

// scala.MatchError: Nok (of class scala.Enumeration$Val)
// 	at repl.Session$App$.foo(
// 	at repl.Session$App$$anonfun$1.apply$mcV$sp(
// 	at repl.Session$App$$anonfun$1.apply(
// 	at repl.Session$App$$anonfun$1.apply(

ADTs, on the other hand, do not suffer from this issue. Here’s a better implementation of Status:

sealed abstract class Status extends Product with Serializable
object Status {
  final case object Ok extends Status
  final case object Nok extends Status

The compiler now has enough information to check whether your pattern matches are exhaustive:

def foo(w: Status): Unit = w match {
  case Status.Ok => println("ok")
// warning: match may not be exhaustive.
// It would fail on the following input: Nok
// def foo(w: Status): Unit = w match {
//                            ^

Checked by