13

I can define a variable (by var) that is immutable:

var x = scala.collection.immutable.Set("aaaaaa","bbbbbb")
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
x += "cccc"
println(x.isInstanceOf[scala.collection.immutable.Set[String]])

This results in:

true
true

+= method is not a member of scala.collection.immutable.Set, so what is happening?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Note that `x` now holds a *new* collection. I think this behaviour is quite intuitive and intended, if you accept other collection methods that work the same way. – Raphael Feb 22 '11 at 21:25
  • Trying it with `val x =` will give you clues to the answer – Luigi Plinge Aug 01 '11 at 20:49

2 Answers2

22

The compiler looks for x.+= ..., and if it can't find it, then it tries to transform the statement into x = x + ... (which only succeeds if x is a var, or x desugars into a call to some update method). Since immutable.Set implements a + operator, and x is a var, this succeeds.

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
6

The original immutable set is still unchanged.

Continuing Ken's answer, the + has created a new set, appended the new item, and returned the new set, leaving the original set object unchanged. So you could say var y = x; y += "cccc" and you would have 2 sets instead of 1:

var x = scala.collection.immutable.Set("aaaaaa","bbbbbb")
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
var y = x
y += "cccc"
println(x)
println(y)
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
println(y.isInstanceOf[scala.collection.immutable.Set[String]])

Getting:

> true
> Set(aaaaaa, bbbbbb)
> Set(aaaaaa, bbbbbb, cccc)
> true
> true

You see the data structure itself is still immutable, but because you declared a var, the assignment is mutable. So it can be repointed to a new object if that is returned. If you change to declaring x as a val, then you couldn't reassign it to a new address.

If you had used a mutable set, then x and y would point to the same object because the + call would have appended the existing set rather than returning a new one (being mutable...):

var x = scala.collection.mutable.Set("aaaaaa","bbbbbb")
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
var y = x
y += "cccc"
println(x)
println(y)

Get:

> Set("aaaaaa","bbbbbb","cccc")
> Set("aaaaaa","bbbbbb","cccc")

Voila.

Community
  • 1
  • 1
Phil H
  • 19,928
  • 7
  • 68
  • 105