2

The docs say:

A collection in package scala.collection.immutable is guaranteed to be immutable for everyone. Such a collection will never change after it is created.

But I don't get the behavior I would expect from this:

scala> var test3 = scala.collection.immutable.Set[String]("one", "two")
test3: scala.collection.immutable.Set[String] = Set(one, two)

scala> test3 += "three"

scala> println(test3)
Set(one, two, three)

What am I missing here?

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
snappymcsnap
  • 2,050
  • 2
  • 29
  • 53
  • 8
    `Set` is immutable but you are reassigning to `var` and `var` is mutable. – Ende Neu Jun 02 '16 at 15:14
  • 6
    `+=` is syntactic sugar, in this case for `test3 = test3 + "three"`. Try making test3 a `val` and you'll encounter a message saying test3 can't be reassigned. – alextsc Jun 02 '16 at 15:14
  • 1
    @EndeNeu - so then why have immutable vs mutable Sets in the first place? Why not just declare them with either var or val depending on what you want? – snappymcsnap Jun 02 '16 at 15:18
  • 2
    @snappymcsnap because the implementation of the mutable and immutable sets are vastly different! – Luka Jacobowitz Jun 02 '16 at 15:22
  • 2
    Keep in mind there is a difference between object mutability, and reference mutability. An object is mutable if the object's properties can be changed. `test3` is a mutable reference to an immutable object, but `test3` can be changed to point to a different object altogether. – Michael Zajac Jun 02 '16 at 16:22

2 Answers2

5

A var can be reassigned (it is a variable, so it can vary). You are then no longer referencing the previous object at all.

A val cannot be reassigned (it is a value, so it cannot vary), but you can call methods on that object, for example if the value is a mutable set.

When I say vary I basically mean that the reference cannot vary. It's a bit confusing, I know.

To put it another way: both vals and vars can point to objects with internal state that itself can change. Like a mutable map.

I encourage you to write a code example yourself that verifies this table:

    | MutableSet                    | ImmutableSet
--------------------------------------------------
var | Reassign. Insert element      | Reassign
val | Insert                        | None of these
Christian Neverdal
  • 5,655
  • 6
  • 38
  • 93
3

There are two things to avoid (if possible) when working with collections. Immutable collections, as you know, are preferred over mutable ones. However, having an immutable collection stored in a mutable variable only "delays" the problem. You moved the mutability along with all the problems it brings from the collection itself to the variable that holds the collection. Either way you have a state.

Ideal solution is to avoid both. That is, to use both immutable collections and immutable fields (vals). For example, a function can be producing an immutable collection and other function can be consuming it, without ever having to keep the collection itself somewhere or modifying it.

slouc
  • 9,508
  • 3
  • 16
  • 41
  • OK that's a pretty good rule of thumb to follow, thanks. So basically using var creates a variable that is sort of temporary...when you first assign it, it points to a specific reference in memory (that is immutable), as soon as you add to it, it creates a brand new immutable Set (with the new item) so the variable is pointing to a brand new reference. I can see how that could get you into trouble. OK so I use val almost like I would use the 'final' keyword in Java to ensure that my immutable is always immutable? – snappymcsnap Jun 02 '16 at 16:32
  • Exactly. Using a var means that the variable can change its value, which means that at some point it holds a reference to some immutable collection, but then later on that reference can be pointing to a completely different immutable collection. Just one thing - I wouldn't necessarily call the var "temporary". I mean, it is, but just as much as any normal variable in Java. It's more correct (pardon the stupid term) to say that var is changeable. Its value can be re-assigned, while with vals that's impossible (you pulled a correct parallel to final in Java). – slouc Jun 02 '16 at 17:01