Skip to content
AgileLogics
5 min read

Case Classes

Prerequisites: Classes

A case class is a class for immutable data. One line gives you a constructor, read-only fields, value-based equality, a readable toString, a copy method, and pattern matching support.

case class Point(x: Int, y: Int)

@main def points(): Unit =
  val a = Point(1, 2)
  val b = Point(1, 2)
  println(a)
  println(a.x)
  println(a == b)
  println(a.copy(y = 10))
  println(Set(a, b).size)
Point(1,2)
1
true
Point(1,10)
1
  • Parameters are automatically val fields.
  • == compares contents: two points with the same coordinates are equal, and they deduplicate in a Set.
  • copy creates a changed copy — case classes are updated by making new values, not by mutation.

Modeling a domain

case class Address(city: String, country: String)
case class Customer(name: String, email: String, address: Address)
case class Order(id: Int, customer: Customer, total: BigDecimal)

@main def domain(): Unit =
  val ada = Customer("Ada", "ada@example.com", Address("London", "UK"))
  val order = Order(1, ada, BigDecimal("59.97"))

  println(order.customer.address.city)
  val moved = order.copy(customer = ada.copy(address = Address("Paris", "FR")))
  println(moved.customer.address)
  println(order.customer.address)
London
Address(Paris,FR)
Address(London,UK)

The original order is unchanged, so it can be shared safely.

Pattern matching on case classes

case class Point(x: Int, y: Int)

def describe(p: Point): String = p match
  case Point(0, 0) => "origin"
  case Point(x, 0) => s"on the x-axis at $x"
  case Point(0, y) => s"on the y-axis at $y"
  case Point(x, y) => s"at ($x, $y)"

@main def matching(): Unit =
  List(Point(0, 0), Point(3, 0), Point(0, -2), Point(4, 5))
    .map(describe)
    .foreach(println)
origin
on the x-axis at 3
on the y-axis at -2
at (4, 5)

Patterns take the value apart into its fields — the Pattern Matching lesson goes further.

Common mistakes

  • Using var fields in case classes. It's allowed, but it breaks the guarantees that make them useful (for example, a changed field changes the hash code of a value already in a Set).