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.”
Problem
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?
Solution
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 :+
method.
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" ^
Summary
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 afinal
variable 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
Vector
andList
) cannot be changed.
The
Array
does not obey the second statement about collections, so I used the word “most” in that sentence rather than “all.” Because the ScalaArray
is backed by a Javaarray
, the elements in anArray
can be changed after theArray
is first created. You can’t make theArray
longer or shorter, but you can re-assign an element, like this:elements(0) = "foo"
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
See Also
- 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.”