Val Set objects and mutability

I’m always trying to use vals rather than vars but not quite sure how to proceed in this case

import collection.mutable.Set
val aSet = Set(1,2,3)
aSet += 5

aSet now equals Set(1,2,3,5) with aSet still pointing to a particular fixed set object since its a val. However its contents can still be adjusted at will.

How would you therefore do aSet = aSet.filter(_ < 4) without hitting the ‘reassigning to a val’ error?

When you use an immutable data structure you create a new object.
You have to reference this new object with a val. So (code not tested):

  import collection.immutable.Set

  val aSet = Set(1,2,3)
  val newSet = aSet + 5
  val filteredSet = newSet.filter(_ < 4)

HTHs.

There is a retain method on mutable sets which does what you need

import collection.mutable.Set
val aSet = Set(1,2,3)
aSet += 5
aSet.retain(_ < 4)

As usual, I found this by a google search leading to Alvin Alexander’s scala cookbook

note that val Will hold the reference to the Set and it can not be reassigned, the problem with mutable data structures is that you don’t change the instance, instead you change it’s internal state, that’s why it leads to many problems. In your case you are using the mutable package of collections, switching to the immutable will lead you to your original thought and will work as expected.

Thanks - In relation to this, I’m never sure how’s best to program entities with constantly updating state. In trying to maximise the use of val’s (as suggested by the books) is it better to have:

i) a val item such as a map or set, that refers to a mutable map or set that updates throughout a program’s execution or:
ii) a var variable that is always updating itself to point to a new immutable map or set?

I end up flip flopping between the two.

[
As I extra related question: these two functions have similar functionality as mentioned above: retain and filter. However why is there a difference in passing in tuple values?: e.g.

scala> x.retain{ (k,v) => v==2 }
res29: scala.collection.mutable.Map[String,Int] = Map(a -> 2)

scala> x.filter{ (k,v) => v==2 }
<console>:14: error: missing parameter type
Note: The expected type requires a one-argument function accepting a 
2-Tuple.
       Consider a pattern matching anonymous function, `{ case (k, v) 
=>  ... }`
        x.filter{ (k,v) => v==2 }

i.e. with filter you have to do x.filter { case (k,v) => v == 2 }

]

i) a val item such as a map or set, that refers to a mutable map or set that updates throughout a program’s execution or:
ii) a var variable that is always updating itself to point to a new immutable map or set?

I’d say it depends on the scope of the map/set. If you really need to mutate the state and you pass it to the outside of the class, I’d use immutable colletions with a var. It will be safer, as you don’t need to remember copying to prevent external changes.

As I extra related question: these two functions have similar functionality as mentioned above: retain and filter. However why is there a difference in passing in tuple values?

This is simply because filter is inherited from TraversableLike and it has to obey the signature from there, which takes a function (A) => Boolean, i.e. a function with a single parameter. This means you have to give a function that accepts a tuple and unpacks it. Using the case syntax here is syntactic sugar for doing a match on the only parameter to a function.

The retain method on the other hand is not inherited from a non-Map type, so it can have a signature more fitting for Maps and takes a function (K, V) => Boolean. So with retain you do not have a tuple at all, but get key and value as separate parameters to your method.
You will notice, that retain on mutable Sets behaves the same as filter (even when your set contains tuples). The two-parameter-predicate version is specific to the Map implementation.