scalabeginner

Enums and Algebraic Data Types

Define enums and ADTs in Scala 3: parameterized enums, sealed hierarchies, and exhaustive matching.

scala
// Simple enum
enum Color:
  case Red, Green, Blue

// Enum with parameters
enum Planet(val mass: Double, val radius: Double):
  case Mercury extends Planet(3.303e+23, 2.4397e6)
  case Venus   extends Planet(4.869e+24, 6.0518e6)
  case Earth   extends Planet(5.976e+24, 6.37814e6)
  case Mars    extends Planet(6.421e+23, 3.3972e6)

  def surfaceGravity: Double = 6.67300e-11 * mass / (radius * radius)
  def surfaceWeight(otherMass: Double): Double = otherMass * surfaceGravity

// ADT with enum
enum Json:
  case JNull
  case JBool(value: Boolean)
  case JNum(value: Double)
  case JStr(value: String)
  case JArr(values: List[Json])
  case JObj(fields: Map[String, Json])

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

// Recursive ADT: expression tree
enum Expr:
  case Num(value: Double)
  case Add(left: Expr, right: Expr)
  case Mul(left: Expr, right: Expr)
  case Neg(expr: Expr)

def eval(expr: Expr): Double = expr match
  case Expr.Num(v)    => v
  case Expr.Add(l, r) => eval(l) + eval(r)
  case Expr.Mul(l, r) => eval(l) * eval(r)
  case Expr.Neg(e)    => -eval(e)

def show(expr: Expr): String = expr match
  case Expr.Num(v)    => v.toString
  case Expr.Add(l, r) => s"(${show(l)} + ${show(r)})"
  case Expr.Mul(l, r) => s"(${show(l)} * ${show(r)})"
  case Expr.Neg(e)    => s"-(${show(e)})"

@main def run(): Unit =
  // Simple enum
  println(Color.values.mkString(", "))
  println(Color.valueOf("Red"))

  // Parameterized enum
  val earthWeight = 75.0
  for planet <- Planet.values do
    println(f"${planet}%-8s: ${planet.surfaceWeight(earthWeight)}%.2f N")

  // JSON ADT
  val json = Json.JObj(Map(
    "name" -> Json.JStr("Alice"),
    "age"  -> Json.JNum(30),
    "tags" -> Json.JArr(List(Json.JStr("scala"), Json.JStr("fp")))
  ))
  println(stringify(json))

  // Expression tree
  val expr = Expr.Add(Expr.Mul(Expr.Num(2), Expr.Num(3)), Expr.Neg(Expr.Num(1)))
  println(s"${show(expr)} = ${eval(expr)}")

Use Cases

  • Domain modeling with algebraic data types
  • JSON representation without libraries
  • Expression tree evaluation

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.