Most of the classes you will ever write do one humble job: hold data. A User is a name and an age; a Point is an x and a y. In Scala you can declare such a class in a single line — the fields live right in the parentheses, no body needed:
class Visitor(val name: String, val age: Int)
But a plain class only stores the data — it doesn't know how to show it or compare it. Every class inherits two defaults: toString prints the class name plus a memory address, and == asks "are these the very same object?" — not "do they hold the same values?".
The trap:
Sooner or later, every Scala beginner prints an object, or compares two objects built from identical values — and gets this:
val a = new Visitor("Ana", 25)
val b = new Visitor("Ana", 25)
println(a) // expecting the data...
println(a == b) // expecting true...
Visitor@1b6d3586
false
No name, no age — just Visitor@ and a hex address. And two visitors with the exact same data are "not equal", because the default equals compares identity (the address), not contents.
The fix — one keyword:
Mark the class with case and the compiler generates the useful versions for you, straight from the constructor parameters (which automatically become public val fields — no val keyword needed):
case class User(name: String, age: Int)
println(User("Ana", 25)) // User(Ana,25) — no `new` needed
println(User("Ana", 25) == User("Ana", 25)) // true — compares values
You also get copy for free: it clones an object while changing only the fields you name — ana.copy(name = "Bob") keeps the age and swaps the name. Since the fields are immutable vals, this is the idiomatic way to get a "changed" version without touching the original.
And copy really is a case-class exclusive — call it on a plain class and the compiler stops you:
-- [E008] Not Found Error: p1.scala:9:14 ---------------------------------------
9 |val other = a.copy(name = "Bob")
| ^^^^^^
| value copy is not a member of Visitor
Assignment
Follow the Coding Tutorial to see the freebies in action — and the plain-class trap right next to them:
- Declare
case class Userwithname: Stringandage: Int. - Create
ana=User("Ana", 25)and print her — the generatedtoStringdoes the formatting. - Create
twinfrom the same values and print whetherana == twin. - Declare a regular
class Visitor(val name: String, val age: Int), buildv1andv2from identical values withnew, and print whetherv1 == v2. - Make
bobwithana.copy(name = "Bob")and print him.
The exact expected output is:
ana = User(Ana,25)
same = true
plain same = false
bob = User(Bob,25)
Hint
If your output looks like User@1b6d3586, you forgot the case keyword. To embed a comparison in a printed string, wrap it in braces: s"same = ${ana == twin}".
Free plan: 30 tutor messages. Premium is unlimited.