Scala Saturday: Dealing with Immutability (2 of 2)

The management and isolation of mutability

In part 1 we learned about the val keyword in Scala which allows you to create a value that cannot be changed after declaration. Let’s look at how to use this in scenarios where we would previously use mutability.

Validation

Jack’s caught in the middle of this mess.

Here we have two functions that return the same value, a user’s name that has been trimmed. They also share the same structure: initialization, “doing stuff”, and returning values (where the last expression of a method is its return value, without requiring a return keyword). However, the two differ in how they get to that return value.

The first method takes the variable, assigns it a new copy from the trim method, and returns the same variable. In the second method the userInput value cannot be changed after declaration. So what do we do? We declare another value that trims the string the same way and return that new value, as opposed to returning the initial value.

Yup, it’s that simple. We can model changes to values by introducing new values. If we had several steps of validation, we could have a new value for each step. We have the advantage of documenting what each step is doing through the value names. Compare the following.

Just J

In the first method, we know that there’s something going on, but none of it is labeled. What is the method returning? Maybe we could solve that with comments. In the second method, no comments are needed. Each value name communicates what it contains. And if you look closely, you can see a small, linear dependency graph. If we reordered the mutable operations in the first example, we couldn’t be sure if we would get the same result. But if we tried to reorder the immutable operations using val , a compilation error would stop us because the expression sides of the values also refer to values, making their relationship to one another much more clear and explicit.

Now that you have both styles at your disposal, which one should you use? The Scala community already has this one covered.

Prefer val over var .

Or more generally,

Prefer immutability over mutability .

In an expressive, multi-paradigm language like Scala, there can be multiple ways to write a solution. The bevy of options can turn into a liability if left unchecked, which is why we have the guidelines above. Notice that it says “prefer” versus “you must use”. Each style has benefits and drawbacks. The mutable style is handy for performance critical loops or holding state, like a counter. The immutable style tends to generate more intermediate structures that need to be garbage collected. But the immutable style is often easier to understand and easier to test. 99% of the time you will want to start with val and immutable patterns, and then move to var and mutability for exceptional cases.

Collections

Let’s see how our new immutable outlook on life works with collections of values. Imagine that we have directions that need some preparation before they get used. We need to add the values "start” and "end" to the directions .

Konami Code not present.

In the mutable example, we only have one variable that is being used and reused. This works, but we would prefer not to use this style. The second example uses a different set of operators that return copies of directions with new information added, while leaving the original collection untouched.

It may be difficult to see, but the approach to avoiding mutability here in the collections example is solved in the same way as the user name example by creating new copies of the data instead of modifying the originals.

Note that the name of the class that holds mutable data must be referred to by a longer name (or imported manually), adding a bit of friction to its usability. We can say that Scala prefers its immutable and read-only structures to its mutable ones. If you choose to use mutability, you want to call attention to it as a warning sign to others.

Scala’s dirty secrets

Those red stars are secrets.

When I first learned Scala, I jumped on the immutability wagon right quick.

The king has deemed it so, everything shall be immutable! We must destroy the mutable evil!

But it’s not good to be dogmatic about things like that (or anything, really). Mutability is a tool in our toolbox that has its place. Here are some places in the Scala standard library that use mutability.

Ooo, so dirty.

The two methods above are slightly modified copies of methods in Scala’s collections library. The first counts the number of eligible elements in a collection given some filter (or “predicate”) p . Here, we are counting the even numbers between 1 and 10, inclusive. The second method collapses the list of numbers into just one number using simple addition (and something called “a zero”, which in this case is literally the number zero).

These two methods and the family of methods just like it all depend on mutability. We could rewrite some of them to use immutability, but the immutable solutions would probably have different performance characteristics. Here, the Scala authors have opted to use the mutable style for performance and flexibility.

Also note that these methods act immutable in a way. Neither of them modify the original collection; they only modify some state internal to their functionality and return the result. No one in the outside world knows if they used immutability or not. The mutability is well contained in each method. There’s no risk of outside forces changing the counter c or result variable res . The mutability is in a tidy package that can be safely mixed with immutable code. By managing the boundary between mutable and immutable code, we’re turning mutability’s liability into an asset that we can take advantage of freely. Therefore immutability isn’t about the eradication of mutability, but more its management and isolation.

Immutability is really about the management and isolation of mutability.

Eventually there will come a time when you need to write mutable code. And you should not feel ashamed. The king will not smite you! We want to use mutability because it is a tool in our toolbox, but use it in a responsible way. We can take that mutability, wrap it in an abstraction, and tie a bow on it with Scaladoc on top. What was once unsafe is now a gift.