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:
foo(Status.Nok)
// scala.MatchError: Nok (of class scala.Enumeration$Val)
// at repl.Session$App$.foo(enumerations_as_adt.md:13)
// at repl.Session$App$$anonfun$1.apply$mcV$sp(enumerations_as_adt.md:22)
// at repl.Session$App$$anonfun$1.apply(enumerations_as_adt.md:22)
// at repl.Session$App$$anonfun$1.apply(enumerations_as_adt.md:22)
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 {
// ^
Linter | Rule |
---|---|
WartRemover |