Enums & Algebraic Data Types

14.1 Simple enums (Scala 3)

enum Color:
  case Red, Green, Blue

Color.Red
Color.values            // Array(Red, Green, Blue)
Color.valueOf("Green")
Color.Red.ordinal       // 0

14.2 Enums with parameters & members

enum Planet(val mass: Double, val radius: Double):
  case Mercury extends Planet(3.303e+23, 2.4397e6)
  case Earth   extends Planet(5.976e+24, 6.37814e6)

  private final val G = 6.67300e-11
  def surfaceGravity: Double = G * mass / (radius * radius)

Planet.Earth.surfaceGravity

14.3 ADTs with enums

enum Shape:
  case Circle(radius: Double)
  case Rectangle(w: Double, h: Double)
  case Triangle(a: Double, b: Double, c: Double)

def area(s: Shape): Double = s match
  case Shape.Circle(r) => math.Pi * r * r
  case Shape.Rectangle(w, h) => w * h
  case Shape.Triangle(a, b, c) =>
    val p = (a + b + c) / 2
    math.sqrt(p * (p - a) * (p - b) * (p - c))

14.4 Generic ADTs

enum Tree[+A]:
  case Leaf
  case Node(left: Tree[A], value: A, right: Tree[A])

  def size: Int = this match
    case Leaf => 0
    case Node(l, _, r) => l.size + 1 + r.size

enum Result[+E, +A]:
  case Ok(value: A)
  case Err(error: E)

14.5 Sealed traits (Scala 2 style ADTs, still common)

sealed trait Json
case object JNull extends Json
case class JBool(b: Boolean) extends Json
case class JNum(n: Double) extends Json
case class JStr(s: String) extends Json
case class JArr(items: List[Json]) extends Json
case class JObj(fields: Map[String, Json]) extends Json

def render(j: Json): String = j match
  case JNull => "null"
  case JBool(b) => b.toString
  case JNum(n) => n.toString
  case JStr(s) => s"\"$s\""
  case JArr(xs) => xs.map(render).mkString("[", ",", "]")
  case JObj(fs) => fs.map((k, v) => s"\"$k\":${render(v)}").mkString("{", ",", "}")

14.6 Making illegal states unrepresentable

enum Connection:
  case Disconnected
  case Connecting(attempt: Int)
  case Connected(sessionId: String)

14.7 Java-compatible enums

enum Level extends java.lang.Enum[Level]:
  case Low, High