पाठ 9 / 25
Case Classes, Enums and ADTs
Model data with case classes, enums and sealed hierarchies.
Algebraic data types
Case classes are concise immutable data types: case class Item(sku: String, qty: Int) generates public val fields, equals/hashCode by value, a readable toString, a copy method for modified copies and pattern-matching support. Enums (Scala 3) define a fixed set of cases, either simple (enum Status { case Placed, Paid, Shipped }) or with parameters and methods, and they interoperate with Java enums when extending java.lang.Enum. Together they express algebraic data types (ADTs): product types (a case class holds this and that) and sum types (an enum or sealed trait is this or that). For example, a payment is Card(last4) or Upi(vpa) or Cash. Because the set of cases is closed, the compiler warns about non-exhaustive matches, so adding a new case shows you every place to update. Modelling the domain precisely with ADTs makes illegal states unrepresentable: rather than a status: String with a nullable trackingId, use Shipped(trackingId) that only exists once shipped.
Modelling payments and order states
Enums with data, exhaustive matches and copy.
enum Payment:
case Card(last4: String)
case Upi(vpa: String)
case Cash
enum OrderState:
case Placed
case Paid(payment: Payment)
case Shipped(payment: Payment, trackingId: String)
case Cancelled(reason: String)
case class Order(id: String, totalPaise: Long, state: OrderState)
def describe(p: Payment): String = p match
case Payment.Card(last4) => s"card ending $last4"
case Payment.Upi(vpa) => s"UPI $vpa"
case Payment.Cash => "cash on delivery"
// removing a case here makes the compiler warn: match may not be exhaustive
val placed = Order("o-1", 49900, OrderState.Placed)
val paid = placed.copy(state = OrderState.Paid(Payment.Upi("asha@okbank")))
val shipped = paid.state match
case OrderState.Paid(p) => paid.copy(state = OrderState.Shipped(p, "TRK123"))
case _ => paid
println(shipped)
println(placed == Order("o-1", 49900, OrderState.Placed)) // true: value equalityvalues exists only for simple enums
EnumName.values and valueOf are generated only when every case is a simple singleton such as enum Status { case Placed, Paid }. Payment and OrderState have parameterised cases, so they do not get values.
त्वरित जाँच: What does making a hierarchy sealed (or using an enum) enable?
- Faster runtime dispatch only
- Mutable fields
- Compiler exhaustiveness checks in pattern matches, because all cases are known
- Multiple inheritance of classes
Answer
Compiler exhaustiveness checks in pattern matches, because all cases are known — A closed set of cases lets the compiler warn when a match misses one.