Immutability
Immutable data never changes after creation. It is the foundation of reliable functional programs.
On this page · 5 min · Intermediate
On this page
- In simple words
- Learning objectives
- Explanation
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 30, 2026
In simple words#
Immutability is like a bank statement: past entries are never edited. A new transaction adds a new statement line, so history is always trustworthy.
- Pure function
- Same input → same output, no side effects.
- Persistent data structure
- New versions share memory with old ones.
- Referential transparency
- An expression can be replaced by its value.
Learning objectives#
- Explain the benefits of immutability
- Write pure functions
- Update state without mutation
- Recognise side effects
Explanation#
Immutable values are safe to share between threads — no locks needed.
Pure functions are easy to test: no hidden state, no surprises.
Instead of changing objects, create new ones with copy or new collections; Scala shares structure so this is cheap.
Keep side effects (printing, database writes) at the edges of the program.
Code example: A cart without mutation#
case class Item(name: String, price: Double, qty: Int)
case class Cart(items: List[Item] = Nil):
def add(item: Item): Cart = copy(items = item :: items)
def remove(name: String): Cart = copy(items = items.filterNot(_.name == name))
def total: Double = items.map(i => i.price * i.qty).sum
val empty = Cart()
val c1 = empty.add(Item("Laptop", 55000, 1))
val c2 = c1.add(Item("Mouse", 700, 2))
val c3 = c2.remove("Laptop")
// Replaying events with foldLeft
val events = List(Item("Pen", 20, 5), Item("Book", 350, 1))
val replayed = events.foldLeft(Cart())(_.add(_))
println(s"${empty.total} ${c1.total} ${c2.total} ${c3.total}")
println(replayed.total)
0.0 55000.0 56400.0 1400.0 450.0
This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- Every operation returns a new Cart.
- Old versions (empty, c1, c2) remain valid.
- foldLeft replays events into a final state.
- total is a pure calculation.
Real-world use case#
Undo/redo, event sourcing and concurrent request handling all become simpler with immutable state.
Common mistakes#
A val holding a mutable.ArrayBuffer can still change. Use immutable collections.
Return values and perform I/O at the edges.
Best practices#
- val + immutable collections
- copy for updates
- Pure core, effects at the edge
- foldLeft to build state
Remember this#
Never change — create new.
Pure functions are easy to test.
Immutable = thread-safe.
Practice exercise#
Your task: Add a method updateQty(name, qty) to Cart that returns a new Cart.
Show solution
def updateQty(name: String, qty: Int): Cart =
copy(items = items.map(i => if i.name == name then i.copy(qty = qty) else i))
Mini quiz#
Immutable objects can be shared between threads without locks.
Want more? Practise all Scala MCQs · Scala interview questions
My notes#
Saved in this browser.