I am currently working on React JS and React Native frameworks. On the half way road I came across Immutability or the Immutable-JS library, when I was reading about Facebook's Flux and Redux implementation.
The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?
Giving an example, let us consider a simple News reader app with the opening screen being a list view of news headlines.
If I set say an array of objects with a value initially I can't manipulate it. That's what immutability principle says, right? (Correct me if I am wrong.) But, what if I have a new News object that has to be updated? In usual case, I could have just added the object to the array. How do I achieve in this case? Delete the store and recreate it? Isn't adding an object to the array a less expensive operation?
PS: If the example is not the right way to explain immutability, please do let me know what's the right practical example.
Once upon a time, there was a problem with data synchronization between threads. This problem was a great pain, there were 10+ solutions. Some people tried to solve it radically. It was a place where functional programming was born. It is just like Marxism. I couldn't understand how Dan Abramov sold this idea into JS, because it is single threaded. He is a genius.
I can give a small example. There is an attribute
__attribute__((pure))
in gcc. Compilers tries to solve whether your function is pure or not if you won't declear it specially. Your function can be pure even your state is mutable. Immutability is just a one of 100+ ways to guarantee that you function will be pure. Actually 95% of your functions will be pure.You shouldn't use any limitations (like immutability) if you actually don't have a serious reason. If you want to "Undo" some state, you can create transactions. If you want to simplify communications you can send events with immutable data. It is up to you.
I am writing this message from post marxism republic. I am sure that radicalization of any idea is a wrong way.
Another benefit of Immutability in Javascript is that it reduces Temporal Coupling, which has substantial benefits for design generally. Consider the interface of an object with two methods:
It may be the case that a call to
baz()
is required to get the object in a valid state for a call tobar()
to work correctly. But how do you know this?To figure it out you need to scrutinise the class internals because it is not immediately apparent from examining the public interface. This problem can explode in a large codebase with lots of mutable state and classes.
If
Foo
is immutable then this is no longer a problem. It is safe to assume we can callbaz
orbar
in any order because the inner state of the class cannot change.I have recently been researching the same topic. I'll do my best to answer your question(s) and try to share what I have learned so far.
Basically it comes down to the fact that immutability increases predictability, performance (indirectly) and allows for mutation tracking.
Predictability
Mutation hides change, which create (unexpected) side effects, which can cause nasty bugs. When you enforce immutability you can keep your application architecture and mental model simple, which makes it easier to reason about your application.
Performance
Even though adding values to an immutable Object means that a new instance needs to be created where existing values need to be copied and new values need to be added to the new Object which cost memory, immutable Objects can make use of structural sharing to reduce memory overhead.
You can read more about this here.
Mutation Tracking
Besides reduced memory usage, immutability allows you to optimize your application by making use of reference- and value equality. This makes it really easy to see if anything has changed. For example a state change in a react component. You can use
shouldComponentUpdate
to check if the state is identical by comparing state Objects and prevent unnecessary rendering. You can read more about this here.Additional resources:
Yes this is correct. If you're confused on how to implement this in your application I would recommend you to look at how redux does this to get familiar with the core concepts, it helped me a lot.
I like to use Redux as an example because it embraces immutability. It has a single immutable state tree (referred to as
store
) where all state changes are explicit by dispatching actions which are processed by a reducer that accepts the previous state together with said actions (one at a time) and returns the next state of your application. You can read more about it's core principles here.There is an excellent redux course on egghead.io where Dan Abramov, the author of redux, explains these principles as follows (I modified the code a bit to better fit the scenario):
Also, these videos demonstrate in further detail how to achieve immutability for:
A Contrarian View of Immutability
Short answer: Immutability is more a fashion trend than a necessity in JavaScript. There are a few narrow cases when it becomes useful (React/Redux mostly), though usually for the wrong reasons.
Long answer: read below.
Well, I'm glad you asked!
Some time ago a very talented guy called Dan Abramov wrote a javascript state management library called Redux which uses pure functions and immutability. He also made some really cool videos that made the idea really easy to understand (and sell).
The timing was perfect. The novelty of Angular was fading, and JavaScript world was ready to fixate on the latest thing that had the right degree of cool, and this library was not only innovative but slotted in perfectly with React which was being peddled by another Silicon Valley powerhouse.
Sad as it may be, fashions rule in the world of JavaScript. Now Abramov is being hailed as a demigod and all us mere mortals have to subject ourselves to the Dao of Immutability... Wether it makes sense or not.
Nothing!
In fact programmers have been mutating objects for er... as long as there has been objects to mutate. 50+ years of application development in other words.
And why complicate things? When you have object
cat
and it dies, do you really need a secondcat
to track the change? Most people would just saycat.isDead = true
and be done with it.YES! .. Of course it does!
Specially in JavaScript, which in practice is most useful used for rendering a view of some state that is maintained elsewhere (like in a database).
Well, you can go the traditional approach and update the
News
object, so your in-memory representation of that object changes (and the view displayed to the user, or so one would hope)...Or alternatively...
You can try the sexy FP/Immutability approach and add your changes to the
News
object to an array tracking every historical change so you can then iterate through the array and figure out what the correct state representation should be (phew!).Fashions come and go buddy. There are many ways to skin a cat.
I am sorry that you have to bear the confusion of a constantly changing set of programming paradigms. But hey, WELCOME TO THE CLUB!!
Now a couple of important points to remember with regards to Immutability, and you'll get these thrown at you with the feverish intensity that only naivety can muster.
1) Immutability is awesome for avoiding race conditions in multi-threaded environments.
Multi-threaded environments (like C++, Java and C#) are guilty of the practice of locking objects when more than one thread wants to change them. This is bad for performance, but better than the alternative of data corruption. And yet not as good as making everything immutable (Lord praise Haskell!).
BUT ALAS! In JavaScript you always operate on a single thread. Even web workers (each runs inside a separate context). So since you can't have a thread related race condition inside your execution context (all those lovely global variables and closures), the main point in favour of Immutability goes out the window.
(Having said that, there is an advantage to using pure functions in web workers, which is that you'll have no expectations about fiddling with objects on the main thread.)
2) Immutability can (somehow) avoid race conditions in the state of your app.
And here is the real crux of the matter, most (React) developers will tell you that Immutability and FP can somehow work this magic that allows the state of your application to become predictable.
Of course this doesn’t mean that you can avoid race conditions in the database, to pull that one off you’d have to coordinate all users in all browsers, and for that you’d need a back-end push technology like WebSockets (more on this below) that will broadcast changes to everyone running the app.
This rather confusing claim simply means that the latest values assigned to a state object (defined by a single user operating within their browser) become predictable. Which is really no progress at all. Because you could have used a plain old mutated variable to track your state and you’d know you’re dealing with the latest information whenever you access it, and this will work with anything but React/Redux.
Why? Because React is special.. and component state is managed via a chain of events that you have no control over and rely on you remembering not to mutate state directly. This has been handled amazingly from a PR perspective, as the React hype has turned a shortcoming into a sexy fashion. Fashion aside, I'd rather see immutability for what it is, ie a tool to plug a gap when your choice of framework does not handle state intuitively.
3) Race conditions are categorically bad.
Well, they might be if you are using React. But they are rare if you pick up a different framework.
Besides, you normally have far bigger problems to deal with… Problems like dependency hell. Like a bloated code-base. Like your CSS not getting loaded. Like a slow build process or being stuck to a monolithic back-end that makes iterating almost impossible. Like inexperienced devs not understanding whats going on and making a mess of things.
You know. Reality. But hey, who cares about that?
4) Immutability makes use of Reference Types to reduce the performance impact of tracking every state change.
Because seriously, if you are going to copy stuff every time your state changes, you better make sure you are smart about it.
5) Immutability allows you to UNDO stuff.
Because er.. this is the number one feature your project manager is going to ask for, right?
6) Immutable state has lots of cool potential in combination with WebSockets
Last but not least, the accumulation of state deltas makes a pretty compelling case in combination with WebSockets, which allows for an easy consumption of state as a flow of immutable events...
Once the penny drops on this concept (state being a flow of events -- rather than a crude set of records representing the latest view), the immutable world becomes a magical place to inhabit. A land of event-sourced wonder and possibility that transcends time itself. And when done right this can definitely make real-time apps easier to accomplish, you just broadcast the flow of events to everyone interested so they can build their own representation of the present and write back their own changes into the communal flow.
But at some point you wake up and realise that all that wonder and magic do not come for free. Unlike your eager colleagues, your stakeholders (yea, the people who pay you) care little about fashion and a lot about the money they pay to build a product they can sell. And the bottom line is that its harder to write immutable code and easier to break it, plus there is little point having an immutable front-end if you don't have a back-end to support it. When (and if!) you finally convince your stakeholders that you should publish and consume events via a push techology like WebSockets, you find out what a pain it is to scale in production.
Now for some advice, should you choose to accept it.
A choice to write JavaScript using FP/Immutability is also a choice to make your application code-base larger, more complex and harder to manage. I would strongly argue for limiting this approach to your Redux reducers.. unless you know what you are doing. In other words: Just Keep It Simple™. You'll be better off in most cases. And where you are not, I would focus on getting the benefits of immutable data flowing through your (whole) app, rather than build a purely functional front-end and call the thing done.
Now, if you are fortunate enough to be able to make choices in your work, then try and use your wisdom (or not) and do what's right by the person who is paying you. You can base this on your experience, on your gut, or whats going on around you (admittedly if everyone is using React/Redux then there a valid argument that it will be easier to find a resource to continue your work).. Alternatively, you can try either Resume Driven Development or Hype Driven Development approaches. They might be more your sort of thing.
In short, the thing to be said for immutability is that it will make you fashionable with your peers, at least until the next craze comes around, by which point you'll be glad to move on.
I've now added this as an article in my blog => Immutability in JavaScript: A Contrarian View. Feel free to reply in there if you have strong feelings you'd like to get off your chest too ;).
I think the main reason pro immutable objects, is keeping the state of the object valid.
Suppose we have an object called
arr
. This object is valid when all the items are the same letter.if
arr
become an immutable object, then we will be sure arr is always in a valid state.Immutability can be tracked in different contexts, but most important would be to track it against the application state and against the application UI.
I will consider the JavaScript Redux pattern as very trendy and modern approach and because you mentioned that.
For the UI we need to make it predictable. It will be predictable if
UI = f(application state)
.Applications (in JavaScript) do change the state via actions implemented using the reducer function.
The reducer function simply takes the action and the old state and returns the new state, keeping the old state intact.
The benefit is: you time-travel the states since all the state objects are saved, and you can render the app in any state since
UI = f(state)
So you can undo/redo easily.
Happens to be creating all these states can still be memory efficient, an analogy with Git is great, and we have the similar analogy in Linux OS with symbolic links (based on the inodes).