This is an excerpt from the Scala Cookbook (partially re-worded for the internet). This is Recipe 10.6, “Understanding Mutable Variables with Immutable Collections.”
You may have seen that mixing a mutable variable (
var) with an immutable collection causes surprising behavior. For instance, when you create an immutable
Vector as a
var, it appears you can somehow add new elements to it:
scala> var sisters = Vector("Melinda") sisters: collection.immutable.Vector[String] = Vector(Melinda) scala> sisters = sisters :+ "Melissa" sisters: collection.immutable.Vector[String] = Vector(Melinda, Melissa) scala> sisters = sisters :+ "Marisa" sisters: collection.immutable.Vector[String] = Vector(Melinda, Melissa, Marisa) scala> sisters.foreach(println) Melinda Melissa Marisa
How can this be?
Though it looks like you’re mutating an immutable collection, what’s really happening is that the
sisters variable points to a new collection each time you use the
sisters variable is mutable — like a non-final field in Java — so it’s actually being reassigned to a new collection during each step. The end result is similar to these lines of code:
var sisters = Vector("Melinda") sisters = Vector("Melinda", "Melissa") sisters = Vector("Melinda", "Melissa", "Marisa")
In the second and third lines of code, the
sisters reference has been changed to point to a new collection.
You can demonstrate that the
Vector itself is immutable. Attempting to mutate one of its elements — which doesn’t involve reassigning the variable — results in an error:
scala> sisters(0) = "Molly" <console>:12: error: value update is not a member of scala.collection.immutable.Vector[String] sisters(0) = "Molly" ^
When you first start working with Scala, the behavior of a mutable variable with an immutable collection can be surprising. To be clear about variables and values:
- A mutable variable (
var) can be reassigned to point at new data.
- An immutable variable (
val) is like a
finalvariable in Java; it can never be reassigned.
To be clear about collections:
- The elements in a mutable collection (like
ArrayBuffer) can be changed.
- The elements in most immutable collections (like
List) cannot be changed.
Arraydoes not obey the second statement about collections, so I used the word “most” in that sentence rather than “all.” Because the Scala
Arrayis backed by a Java
array, the elements in an
Arraycan be changed after the
Arrayis first created. You can’t make the
Arraylonger or shorter, but you can re-assign an element, like this:
elements(0) = "foo"
- Recipe 20.2, “Prefer Immutable Objects”, discusses the use of mutable variables with immutable collections, and its opposite, using immutable variables with mutable collections as a “best practice.”