DEV Community

Discussion on: Why use immutability?

Collapse
 
bobbypriambodo profile image
Bobby Priambodo • Edited

For me, immutability means clarity and understandability. Consider the following Java snippet:

SomeObj someObj = new SomeObj();
doSomethingOnObj(someObj);
doSomethingWithObj(someObj);
// how does someObj look like at this point?

Looking at this piece of code alone, can you determine instinctively what is the state of someObj after all the statements have been executed?

Simply put, you can't. In languages where mutability is the default (e.g. in Java), any method that receives an object pointer (reference) are free to do anything to the referenced object. And, speaking from experience, bugs related to this behavior has bitten me more than I want.

"But that should not be a problem with properly named methods!" Oh, but names can be misleading too. Going by the name alone, doSomethingOnObj is expected to somehow change someObj in one way or another, while doSomethingWithObj is not expected to mutate. But language-wise, there's nothing stopping developers chased by deadlines to put mutating code in any of those methods. As such, you don't have any confidence on the state of someObj without digging to both methods' implementations and see where the mutations take place (which of course can be hidden in a chain of nested method calls).

In immutable-by-default languages, such as Haskell, OCaml, Elixir, etc. such things are simply not possible to happen. After creation, entities are immutable, and you can only return a copy (with modifications) of those entities. Now, suppose Java is immutable, let's look at the following code:

SomeObj someObj = new SomeObj();
someObj = doSomethingOnObj(someObj);  // someObj's reference/binding is updated
doSomethingWithObj(someObj);

After executing those statements, someObj is guaranteed to be the same as what it was on line 2. Line 3 is not possible at all to change someObj in any way. To know what the state of someObj is, you only need to look at the implementation of doSomethingOnObj (which, hopefully, is properly represented by the function name), and you can be sure doSomethingWithObj has absolutely nothing to do with it.

Readers might argue that line 2 is mutating someObj; it's not. It's called rebinding. Elixir is one language that is immutable but allows rebinding, which prevents the use of intermediate variables. Consider again the following code:

SomeObj someObj = new SomeObj();
SomeObj otherObj = doSomethingOnObj(someObj);
doSomethingWithObj(someObj);

In this snippet, we are guaranteed that doSomethingOnObj will not in any way modify someObj, because the return value is assigned to a different variable. Which definitely contributes significantly on how we can understand the code at hand.

Hope it helps!