9

I'm reading the Programming in Scala book by the Scala Creator and I'm a bit confuse on the example of Set.

Here it is for Immutable Set:

var jetSet = Set("Boeing", "Airbus")
jetSet += "Lear"
println(jetSet.contains("Cessna"))

What's the point of this?

The set is immutable but the variable jetSet is mutable. 1) So every time I add to the set with += it creates a new set? So the variable point to a new set in memory?

2) Shouldn't it be: val jetSet = set("cow","sheep","duck") ? Why does it have to be a var? Is there a reason to use var for a immutable set?

mythicalprogrammer
  • 4,647
  • 6
  • 35
  • 42

4 Answers4

17

The advantage of immutable data structures, in this case Set, is that they are persistent. For example:

var jetSet1 = Set("Boeing", "Airbus")
val jetSet2 = jetSet1 // ... imagine jetSet2 is somewhere else in the program
jetSet1 += "Lear"
assert(!jetSet2.contains("Lear"))

Immutability of these Set objects makes it easier to reason about the program because updates to the jetSet1 variable don't have side effects in other parts of the code (in this case, wherever jetSet2 is used). Although it's not clear from this example, there are occasions when it's convenient to store immutable values in mutable var references; most often, the var will have a limited scope (e.g., local to a function).

Immutable data structures often have clever implementations that are quite efficient. Unfortunately, the Scala collection API is not well documented regarding performance, but I would expect most operations to be roughly O(log N) time. For example, given a large immutable Set s, one should be able to efficiently construct s + x, a new Set with an extra element. Of course, immutability guarantees that s is also preserved. Under the hood, s and s+x will be stored using some kind of tree data-structures with shared components.

The title of your question suggest you are also looking for advice about using val or var. The rule of thumb is to use val whenever you can conveniently. If a var is necessary, then try to limit the variable's scope as much as possible.

Kipton Barros
  • 21,002
  • 4
  • 67
  • 80
  • 3
    Not directly in the API but performance *is* [documented](http://www.scala-lang.org/docu/files/collections-api/collections.html). – Debilski Jun 27 '11 at 08:34
  • 1
    Many operations are, as you expect, O(log n), but it should be pointed out that the base of the logarithm is so high as to make them effectively O(1) operations. Practically speaking, operations on Scala's immutable data structures are within a constant factor of the corresponding operations on their mutable cousins. – Aaron Novstrup Jun 28 '11 at 22:32
  • 1
    Speaking mathematically, one of course neglects the base of the logarithm in big-O notation because it affects only the constant prefactor. Agreed that O(log N) can be really fast for practical purposes. One thing that can make immutable data structures costly is the pressure on the garbage collector. – Kipton Barros Jul 05 '11 at 21:26
6

var allows you to reassign to a variable, think of it as a normal variable declaration in Java. But in the above case, even though you are reassigning to the same variable, it's always a different set since you are using an immutable one.

The point of the example was to show that even if you try "modifying" an immutable collection, the modifications create a new collection instead of touching the original one. If the author would have used a val (along the lines of final in Java), he would have to introduce a variable in scope to hold the new immutable set. I think var was probably used to keep the example simple.

Sanjay T. Sharma
  • 22,857
  • 4
  • 59
  • 71
1

I too was faced with the same question. Tried a few snippets and seem to have understood the difference.

    // immutable reference to an immutable object
    val seta = Set("A", "B")
    seta += "C" //throws an error as the object is immutable
    seta = Set("C") //throws error as the reference is immutable

    // mutable reference to an immutable object
    var seta = Set("A", "B")
    val setab = seta //backup the reference
    set += "C" //creates and new object
    println(setab == seta) //false as seta is a dfferent object now

    //immutable reference to mutable object
    val seta = mutable.Set("A", "B")
    val setab = seta //backup the reference
    set += "C" //modifies the existing object
    println(setab == seta) //true as seta is the same object and same as 
    setab
char
  • 2,063
  • 3
  • 15
  • 26
S Datta
  • 11
  • 1
0

you cannot do += if you use val. the val/var/def applies to the symbol and not to its value/implementation try val...you will get a compile error.

Rathakrishnan Ramasamy
  • 1,612
  • 2
  • 25
  • 46
Mohit
  • 17
  • 1