Scala Language Case Classes Case Classes and Immutabilty


The Scala compiler prefixes every argument in the parameter list by default with val. This means that, by default, case classes are immutable. Each parameter is given an accessor method, but there are no mutator methods. For example:

case class Foo(i: Int)

val fooInstance = Foo(1)
val j = fooInstance.i       // get
fooInstance.i = 2           // compile-time exception (mutation: reassignment to val)

Declaring a parameter in a case class as var overrides the default behavior and makes the case class mutable:

case class Bar(var i: Int)

val barInstance = Bar(1)
val j = barInstance.i       // get
barInstance.i = 2           // set

Another instance when a case class is 'mutable' is when the value in the case class is mutable:

import scala.collection._

case class Bar(m: mutable.Map[Int, Int])

val barInstance = Bar(mutable.Map(1 -> 2))
barInstance.m.update(1, 3)                  // mutate m
barInstance                                 // Bar(Map(1 -> 3)

Note that the 'mutation' that is occurring here is in the map that m points to, not to m itself. Thus, if some other object had m as a member, it would see the change as well. Note how in the following example changing instanceA also changes instanceB:

import scala.collection.mutable

case class Bar(m: mutable.Map[Int, Int])

val m = mutable.Map(1 ->2)
val barInstanceA = Bar(m)
val barInstanceB = Bar(m)
barInstanceA  // Bar = Bar(Map(1 -> 3))
barInstanceB  // Bar = Bar(Map(1 -> 3))
m  // scala.collection.mutable.Map[Int,Int] = Map(1 -> 3)