Case classes
Most classes in a Scala program are plain data: a user, an order, an event. Put case in front of class and the compiler writes the boilerplate for you. Every parameter becomes a public val; == compares the contents, not identity; toString prints the fields; hashCode agrees with == so instances work as Map keys and in Sets; copy makes a modified copy; and a companion with apply and unapply is generated, which is what makes case classes work in patterns.
case class User(name: String, age: Int, role: String = "member")
@main def run(): Unit =
val a = User("Asha", 30)
val b = User("Asha", 30)
println(a)
println(a == b)
println(a.name)
val older = a.copy(age = 31)
val admin = a.copy(role = "admin")
println(older)
println(admin)
println(a)
println(Set(a, b, older).size)User(Asha,30,member)
true
Asha
User(Asha,31,member)
User(Asha,30,admin)
User(Asha,30,member)
2Compare this with the plain class in Module 04, where two objects with the same fields were not equal. copy uses named and default arguments: name the fields you want to change, and the rest are copied. a itself never changes.
Put a and admin into a Set and print its size. Are they equal?
Reassigning a case class field
case class Point(x: Int, y: Int)
@main def run(): Unit =
val p = Point(1, 2)
p.x = 10
println(p)-- [E052] Type Error: Main.scala:5:6
5 | p.x = 10
| ^^^^^^^^
| Reassignment to val x
1 error found
Compilation failedCase class parameters are vals: a case class is an immutable value, like the number 5. Nobody holding a reference to p can have it change under them, which is what makes case classes safe to share between functions and threads.
Make a new value with copy. It is cheap, and the old value stays valid for anyone still using it.
case class Point(x: Int, y: Int)
@main def run(): Unit =
val p = Point(1, 2)
val moved = p.copy(x = 10)
println(moved)case class Counter(var n: Int), but almost nobody does: a mutable field breaks the "equal now means equal forever" promise that Set and Map rely on.