Scala · OOP & Functional Programming

Immutability

Immutable data never changes after creation. It is the foundation of reliable functional programs.

Intermediate 5 min Lesson 16 of 25Examples use Scala 3 (3.3 LTS or newer) with sbt or scala-cli.
Before you start:Higher-Order Functions
0/25 in Scala
On this page · 5 min · Intermediate

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#

ScalaA cart without mutation Illustrative
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)
Expected output
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#

  1. Every operation returns a new Cart.
  2. Old versions (empty, c1, c2) remain valid.
  3. foldLeft replays events into a final state.
  4. 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#

Hidden mutation in “immutable” classes

A val holding a mutable.ArrayBuffer can still change. Use immutable collections.

Side effects in business logic

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
Scala Illustrative
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#

Immutability quizTrue or false Question 1 of 1

Immutable objects can be shared between threads without locks.

Score so far: 0/0

Want more? Practise all Scala MCQs · Scala interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.