Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Data Structures  ›  Capstone Project

Mutable Collections

Mutable Collections 14 minScala's default collections are immutable; the scala.collection.mutable package offers versions such as ArrayBuffer and mutable.Map that change in place, and you pick one or the other deliberately.

Mutable Collections

On race day, the timing desk records each finisher as they cross the line, hundreds of times in a few minutes. Building a fresh immutable list for every finisher is possible, but sometimes you want one collection that changes in place. Scala has those too; you just have to ask for them by name.

The rule

Immutable is the default; mutable must be imported and chosen on purpose.

Every collection so far, List, Vector, Set and Map, has been immutable. The changeable versions live in the package scala.collection.mutable:

import scala.collection.mutable

val finishers = mutable.ArrayBuffer("Chen", "Asha")
finishers += "Ben"            // ArrayBuffer(Chen, Asha, Ben)
finishers -= "Asha"           // removes the first "Asha"
finishers(0) = "Chen (PB)"    // replace by position

val totals = mutable.Map("Asha" -> 13.5)
totals("Ben") = 6.0           // add a key
totals("Asha") += 3.2         // update in place: now 16.7
  • ArrayBuffer is a growable sequence: adding and removing at the end is cheap, and reading by position is fast.
  • mutable.Map and mutable.Set change in place with +=, -= and assignment by key.
  • Importing the package and writing mutable. in front of the name tells every reader which collections can change.

There are now two ways to keep a log that grows. Compare them:

var log = List(5.0, 8.5)                     // immutable list, reassignable name
log :+= 3.2                                  // log = log :+ 3.2, a new list

val buffer = mutable.ArrayBuffer(5.0, 8.5)   // fixed name, changing contents
buffer += 3.2                                // the same buffer, one more element

Note that log += 3.2 does not compile for a List, because a List has no +=; :+= is the form that works.

The shortcut

Use the "who can see it?" rule. If a collection is built up inside one function and then handed out, a mutable buffer inside is fine: fill it, then return buffer.toList, an immutable copy. If other parts of the program hold on to it, keep it immutable so nothing can change it underneath them.

Recording finishers at the timing deskStep 1 of 4
  1. Inside one function

    Create val finishers = mutable.ArrayBuffer[String](). Only this function can see it.

The trap: thinking a val protects a mutable collection. val only fixes which buffer the name refers to; the buffer's contents can still change.

Drills

Answer fast — trust the rule.

quick drill

What must you write before using mutable.ArrayBuffer?

quick drill

val buf = mutable.ArrayBuffer(5.0) then buf += 8.5. What happens?

quick drill

var log = List(5.0) then log :+= 8.5. What is log now?

quick drill

What is the default choice for a collection that many parts of the program read?

quick drill

A function collects race finishers in a buffer. What should it return?

Remember

  • Collections are immutable by default; mutable ones come from scala.collection.mutable.
  • Ask "who can see it?": mutate privately, and hand out immutable snapshots with toList.
  • Trap: a val does not freeze a mutable collection's contents.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainDesigning the timing desk

Design the race-day timing desk: a function records finishers as they cross the line and then hands the results to the rest of the program. Explain which collection you use inside the function, what it returns, and why, comparing it with a var holding an immutable List.