Amir Esmaeilzadeh
Amir Esmaeilzadeh

Reputation: 1342

'val' or 'var', mutable or immutable?

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?

Upvotes: 13

Views: 3176

Answers (2)

Ken Bloom
Ken Bloom

Reputation: 58770

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.

Upvotes: 22

Phil H
Phil H

Reputation: 20141

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.

Upvotes: 6

Related Questions