I'm in the process of reading Programming in Scala, 2nd Edition (fantastic book, much better than the scala's website for explaining things in a non-rockety-sciencey manner) and I noticed this...oddity when going over Immutable and Mutable Sets.
It declares the following as an immutable set
var jetSet=Set("Boeing", "Airbus")
jetSet+="Lear"
println(jetSet.contains("Cessna"))
And then states that only Mutable sets define the += method. Ok that makes perfect sense. The problem is that this code works. And the type of set created when tested in the REPL is in fact the immutable set, but it has the += method defined on it and it functions perfectly fine. Behold
scala> var a = Set("Adam", "Bill")
a: scala.collection.immutable.Set[String] = Set(Adam, Bill)
scala> a += "Colleen"
scala> println(a)
Set(Adam, Bill, Colleen)
scala> a.getClass
res8: Class[_ <: scala.collection.immutable.Set[String]] = class scala.collection.immutable.Set$Set3
But if I declare the Set to be a val, the Immutable Set created does not have the += method defined
scala> val b = Set("Adam", "Bill")
b: scala.collection.immutable.Set[String] = Set(Adam, Bill)
scala> b += "Colleen"
<console>:9: error: value += is not a member of scala.collection.immutable.Set[String]
b += "Colleen"
What is going on here? They both are stated to be an immutable Set but the one declared a var has access to the += method and can use it.
Also when I kept calling the getClass method on the var Immutable Set I noticed something strange....
scala> a.getClass
res10: Class[_ <: scala.collection.immutable.Set[String]] = class scala.collection.immutable.Set$Set3
scala> a += "One"
scala> a.getClass
res12: Class[_ <: scala.collection.immutable.Set[String]] = class scala.collection.immutable.Set$Set4
scala> a += "Two"
scala> a.getClass
res14: Class[_ <: scala.collection.immutable.Set[String]] = class scala.collection.immutable.HashSet$HashTrieSet
scala> a += "Tree"
scala> a.getClass
res16: Class[_ <: scala.collection.immutable.Set[String]] = class scala.collection.immutable.HashSet$HashTrieSet
scala> a
res17: scala.collection.immutable.Set[String] = Set(One, Tree, Bill, Adam, Two, Colleen)
My guess is that thanks to some hidden syntactic sugar, Scala recognizes that it's a Var and allows you to replace it with a newly constructed set anyway.
Set
is immutable, buta
is mutable, adding an element to the set creates a new set and the result is assigned toa
, ifa
is a val, it is immutable and you can't reassign to it. – Ende Neu