Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Immutable Set is Mutable when declaring as a var

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.

like image 407
Adam Ritter Avatar asked Oct 20 '14 15:10

Adam Ritter


1 Answers

What's mutable is not the Set, is the reference to it.

a += "Colleen"

returns a new immutable set, assigned to the mutable variable a

Scala performs a syntactic transformation, turning the expression into

a = a + "Colleen"

in case += is not defined (as in the case of an immutable Set)

Clearly += doesn't make sense when a is a val, since you cannot reassign it, hence is forbidden.

Here's an extract taken from Programming in Scala (Section 17.3)

To make it easier to switch from immutable to mutable collections, and vice versa, Scala provides some syntactic sugar. Even though immutable sets and maps do not support a true += method, Scala gives a useful alternate interpretation to +=. Whenever you write a += b, and a does not support a method named +=, Scala will try interpreting it as a = a + b

If you keep reading in that section, you'll find a more thorough explanation, with examples.

like image 133
Gabriele Petronella Avatar answered Oct 13 '22 02:10

Gabriele Petronella