Scala Saturday: Dealing with Immutability (1 of 2)

Values vs variables

One of the first things you learn about Scala is that you can declare either values or variables. The difference is that variables can be reassigned after declaration and values cannot. We can say that variables are mutable and values are immutable.

The Fountain of Youth is actually a var.

On its face, this idea of not being able to change anything after declaration might feel absurd. How can you get anything done if you can’t change a variable? Where does the code that does stuff go? How can I face my loved ones? What will the guys down at the lodge think?

Before your brain melts, let’s first take a look at some pitfalls involving mutability that you may have encountered.

Diamond thieves

We’re working with the precious HopeDiamond . We want to acquire a jewel and then appraise it by seeing it shine() .

I love… diamonds.

Someone was nice enough to provide this fun prepareWorkspace routine. But what is it really doing? Under the guise of initialization, it manipulates the jewel some of the time. What is it doing changing another variable? If jewel is set to null , the call to the shine() method would throw a NullPointerException . No good!

We don’t want to write code that we can’t trust.

Was changing jewel something we wanted to allow? Should we write code that takes into account if jewel isn’t available? Sure, we could add a guard before calling shine() to check if jewel is null and then come up with some alternate behavior.

50% of the time I’m 100% sad.

This idea of null checking is extremely common. It usually happens at the top of a subroutine, but in this case it is happening on the way out. Even in this small block of code, there’s a bit of confusion and distrust. In a much larger code base, this type of problem would be even harder to notice. Also, the result of this subroutine is muddled by the alternate case for null . That code pollution is a huge bummer.

Because we’re allowed to change (or “mutate”) jewel , it becomes untrustworthy. Its potential unavailability becomes a mental burden. We must always check for null before every method call or never write code that sets it to something unusable. We don’t want to write code that we can’t trust. But having to think about those edge cases for every single variable can be stressful and ultimately fallible.

Shifting sands

Here’s a different scenario that uses var but without any null problems.

Hot.

Let’s say we want to analyze some geographic data. In this case, we want to count the number of deserts in the world given from getDeserts . The answer should be 5 .

One day, another code contributor decides to add an extra bit of analysis to your subroutine. She says, why not look for an interesting subset of data while we’re here? In this case, we’re isolating Seq("gobi", "arabian", "kalahari") . Because of this subCount addition, we now have an unintended consequence. After changing the deserts variable, our outer subroutine counts the wrong set of data.

This problem is similar to the earlier example with the precious jewel. We didn’t expect our initial data to change. If we didn’t code for the alternate cases, our program could crash or report back bad results.

Is there a way we can communicate to ourselves and our contributors that a certain variable shouldn’t change? Is there a way to prevent it from being changed at all?

Valued members

Immutability to the rescue! The val keyword will tell the Scala compiler to prevent any changes to a value. And if someone tried, they wouldn’t get very far because the code would not compile. With this keyword we are preventing an entire class of bugs related to surprise mutability. The compiler will guarantee that a given value will always be available as declared for its lifetime.

val is for valuables

This brings us to our first big idea in statically-typed languages like Scala.

Push validation into the compiler.

Scala has many mechanisms like val and its type system that can improve the safety of our program and help us more clearly state our intentions. When possible, we want to encode restrictions about our program and have the compiler validate those restrictions at compile time. By stating upfront that we have immutable values, we won’t ever waste time with mutable variables at runtime.

For some, changing variables is an act as fundamental and innocent as breathing air! But as we’ve seen from the scenarios above, there can be some pitfalls.