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?
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.
The question is, why is immutability so important? What is wrong in
mutating objects? Doesn't it make things simple?
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.
All updates return new values, but internally structures are shared to
drastically reduce memory usage (and GC thrashing). This means that if
you append to a vector with 1000 elements, it does not actually create
a new vector 1001-elements long. Most likely, internally only a few
small objects are allocated.
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:
The Dao of Immutability
Immutable Data Structures and JavaScript
Immutability in JavaScript
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 & recreate it?
Isn't adding an object to the array a less expensive operation?
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):
import React from 'react';
import ReactDOM from 'react-dom';
// Reducer.
const news = (state=[], action) => {
switch(action.type) {
case 'ADD_NEWS_ITEM': {
return [ ...state, action.newsItem ];
}
default: {
return state;
}
}
};
// Store.
const createStore = (reducer) => {
let state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(cb => cb !== listener);
};
};
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach( cb => cb() );
};
dispatch({});
return { subscribe, getState, dispatch };
};
// Initialize store with reducer.
const store = createStore(news);
// Component.
const News = React.createClass({
onAddNewsItem() {
const { newsTitle } = this.refs;
store.dispatch({
type: 'ADD_NEWS_ITEM',
newsItem: { title: newsTitle.value }
});
},
render() {
const { news } = this.props;
return (
<div>
<input ref="newsTitle" />
<button onClick={ this.onAddNewsItem }>add</button>
<ul>
{ news.map( ({ title }) => <li>{ title }</li>) }
</ul>
</div>
);
}
});
// Handler that will execute when the store dispatches.
const render = () => {
ReactDOM.render(
<News news={ store.getState() } />,
document.getElementById('news')
);
};
// Entry point.
store.subscribe(render);
render();
Also, these videos demonstrate in further detail how to achieve immutability for:
Arrays
Objects
A Contrarian View of Immutability
TL/DR: Immutability is more a fashion trend than a necessity in JavaScript. If you are using React it does provide a neat work-around to some confusing design choices in state management. However in most other situations it wont add enough value over the complexity it introduces, serving more to pad up a resume than to fulfill an actual client need.
Long answer: read below.
Why is immutability so important(or needed) in javascript?
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.
What is wrong in mutating objects?
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 second cat to track the change? Most people would just say cat.isDead = true and be done with it.
Doesn't (mutating objects) make things simple?
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).
What if I have a new News object that has to be updated? ... How do I achieve in this case? Delete the store & recreate it? Isn't adding an object to the array a less expensive operation?
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!).
I am trying to learn what's right here. Please do enlighten me :)
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.
Nor does it mean that there is some inherent problem in JavaScript where your application state needs immutability in order to become predictable, any developer that has been coding front-end applications before React would tell you this.
This rather confusing claim simply means that if you use React your application is prone to race conditions, but that immutability allows you to take that pain away. Why? Because React is special.. its been designed first and foremost as a highly optimised rendering library with state management subverted to that aim, and thus component state is managed via an asynchronous chain of events (aka "one-way data binding") that optimize rendering but you have no control over and rely on you remembering not to mutate state directly...
Given this context, its easy to see how the need for immutability has little to do with JavaScript and a lot to do with React: if have a bunch of inter-dependent changes in your spanking new application and no easy way to figure out what your state is currently at, you are going to get confused, and thus it makes perfect sense to use immutability to track every historical change.
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 philosophy or 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 code for immutability 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... And IF you are going to go ahead and use immutability regardless, then apply immutable state to your whole application stack, and not just the client-side. After all, there is little point having an immutable front-end, and then connect it to a database where all records have a single mutable version... you just go back to the same problems you were trying to get away from!
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.
Now after this session of self-therapy I'd like to point out that I've 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 ;).
The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?
Actually, the opposite is true: mutability makes things more complicated, at least in the long run. Yes, it makes your initial coding easier because you can just change things wherever you want, but when your program goes bigger it becomes a problem – if a value changed, what changed it?
When you make everything immutable, it means data can't be changed by surprise any more. You know for certain that if you pass a value into a function, it can't be changed in that function.
Put simply: if you use immutable values, it makes it very easy to reason about your code: everyone gets a unique* copy of your data, so it can't futz with it and break other parts of your code. Imagine how much easier this makes working in a multi-threaded environment!
Note 1: There is a potential performance cost to immutability depending on what you're doing, but things like Immutable.js optimise as best they can.
Note 2: In the unlikely event you weren't sure, Immutable.js and ES6 const mean very different things.
In usual case, I could have just added the object to the array. How do I achieve in this case? Delete the store & 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.
Yes, your news example is perfectly good, and your reasoning is exactly right: you can't just amend your existing list, so you need to create a new one:
var originalItems = Immutable.List.of(1, 2, 3);
var newItems = originalItems.push(4, 5, 6);
Although the other answers are fine, to address your question about a practical use case (from the comments on the other answers) lets step outside your running code for a minute and look at the ubiquitous answer right under your nose: git. What would happen if every time you pushed a commit you overwrote the data in the repository?
Now we're in to one of the problems that immutable collections face: memory bloat. Git is smart enough to not simply make new copies of files every time you make a change, it simply keeps track of the diffs.
While I don't know much about the inner workings of git, I can only assume it uses a similar strategy to that of libraries you reference: structural sharing. Under the hood the libraries use tries or other trees to only track the nodes that are different.
This strategy is also reasonably performant for in-memory data structures as there are well-known tree-operation algorithms that operate in logarithmic time.
Another use case: say you want an undo button on your webapp. With immutable representations of your data, implementing such is relatively trivial. But if you rely on mutation, that means you have to worry about caching the state of the world and making atomic updates.
In short, there's a price to pay for immutability in runtime performance and the learning curve. But any experienced programmer will tell you that debugging time outweighs code-writing time by an order of magnitude. And the slight hit on runtime performance is likely outweighed by the state-related bugs your users don't have to endure.
The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?
About mutability
Nothing is wrong in mutability from technical point of view. It is fast, it is re-using the memory. Developers are use to it from the beginning (as I remember it). Problem exists in the use of mutability and troubles which this use can bring.
If object is not shared with anything, for example exists in the scope of the function and is not exposed to the outside, then it is hard to see benefits in immutability. Really in this case it is no sense to be immutable. The sense of immutability starts when something is shared.
Mutability headache
Mutable shared structure can easily create many pitfalls. Any change in any part of the code with access to the reference has impact to other parts with visibility of this reference. Such impact connects all parts together, even when they should not be aware of different modules. Mutation in one function can crash totally different part of the app. Such thing is a bad side effect.
Next often problem with mutation is corrupted state. Corrupted state can happen when mutation procedure fails in the middle, and some fields were modified and some not.
What’s more, with mutation it is hard to track the change. Simple reference check will not show the difference, to know what changed some deep check needs to be done. Also to monitor the change some observable pattern needs to be introduced.
Finally, mutation is reason of the trust deficit. How you can be sure that some structure has wanted value, if it can be mutated.
const car = { brand: 'Ferrari' };
doSomething(car);
console.log(car); // { brand: 'Fiat' }
As above example shows, passing mutable structure always can finish by having different structure. Function doSomething is mutating the attribute given from outside. No trust for the code, you really don't know what you have and what you will have. All these problems take place because: Mutable structures are representing pointers to the memory.
Immutability is about values
Immutability means that change is not done on the same object,structure, but change is represented in new one. And this is because reference represents value not only memory pointer. Every change creates new value and doesn't touch the old one. Such clear rules gives back the trust and code predictability. Functions are safe to use because instead of mutation, they deal with own versions with own values.
Using values instead of memory containers gives certainty that every object represents specific unchangeable value and it is safe to use it.
Immutable structures are representing values.
I am diving even more into the subject in medium article - https://medium.com/#macsikora/the-state-of-immutability-169d2cd11310
Why is immutability so important(or needed) in JavaScript?
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.
new state = r(current state, action)
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).
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:
class Foo {
baz() {
// ....
}
bar() {
// ....
}
}
const f = new Foo();
It may be the case that a call to baz() is required to get the object in a valid state for a call to bar() to work correctly. But how do you know this?
f.baz();
f.bar(); // this is ok
f.bar();
f.baz(); // this blows up
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 call baz or bar in any order because the inner state of the class cannot change.
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.
A Different Take...
My other answer addresses the question from a very practical standpoint, and I still like it. I've decided to add this as another answer rather than an addendum to that one because it is a boring philosophical rant which hopefully also answers the question, but doesn't really fit with my existing answer.
TL;DR
Even in small projects immutability can be useful, but don't assume that because it exists it's meant for you.
Much, much longer answer
NOTE: for the purpose of this answer I'm using the word 'discipline' to mean self-denial for some benefit.
This is similar in form to another question: "Should I use Typescript? Why are types so important in JavaScript?". It has a similar answer too. Consider the following scenario:
You are the sole author and maintainer of a JavaScript/CSS/HTML codebase of some 5000 lines. Your semi-technical boss reads something about Typescript-as-the-new-hotness and suggests that we may want to move to it but leaves the decision to you. So you read about it, play with it, etc.
So now you have a choice to make, do you move to Typescript?
Typescript has some compelling advantages: intellisense, catching errors early, specifying your APIs upfront, ease of fixing things when refactoring breaks them, fewer tests. Typescript also has some costs: certain very natural and correct JavaScript idioms can be tricky to model in it's not-especially-powerful type system, annotations grow the LoC, time and effort of rewriting existing codebase, extra step in the build pipeline, etc. More fundamentally, it carves out a subset of possible correct JavaScript programs in exchange for the promise that your code is more likely to be correct. It's arbitrarily restrictive. That's the whole point: you impose some discipline that limits you (hopefully from shooting yourself in the foot).
Back to the question, rephrased in the context of the above paragraph: is it worth it?
In the scenario described, I would contend that if you are very familiar with a small-to-middling JS codebase, that the choice to use Typescript is more aesthetic than practical. And that's fine, there's nothing wrong with aesthetics, they just aren't necessarily compelling.
Scenario B:
You change jobs and are now a line-of-business programmer at Foo Corp. You're working with a team of 10 on a 90000 LoC (and counting) JavaScript/HTML/CSS codebase with a fairly complicated build pipeline involving babel, webpack, a suite of polyfills, react with various plugins, a state management system, ~20 third-party libraries, ~10 internal libraries, editor plugins like a linter with rules for in-house style guide, etc. etc.
Back when you were 5k LoC guy/girl, it just didn't matter that much. Even documentation wasn't that big a deal, even coming back to a particular portion of the code after 6 months you could figure it out easily enough. But now discipline isn't just nice but necessary. That discipline may not involve Typescript, but will likely involve some form of static analysis as well as all the other forms of coding discipline (documentation, style guide, build scripts, regression testing, CI). Discipline is no longer a luxury, it is a necessity.
All of this applied to GOTO in 1978: your dinky little blackjack game in C could use GOTOs and spaghetti logic and it just wasn't that big a deal to choose-your-own-adventure your way through it, but as programs got bigger and more ambitious, well, undisciplined use of GOTO could not be sustained. And all of this applies to immutability today.
Just like static types, if you are not working on a large codebase with a team of engineers maintaining/extending it, the choice to use immutability is more aesthetic than practical: it's benefits are still there but may not outweigh the costs yet.
But as with all useful disciplines, there comes a point at which it is no longer optional. If I want to maintain a healthy weight, then discipline involving ice cream may be optional. But if I want to be a competitive athlete, my choice of whether or not to eat ice cream is subsumed by my choice of goals. If you want to change the world with software, immutability might be part of what you need to avoid it collapsing under it's own weight.
Take for example:
const userMessage = {
user: "userId",
topic: "topicId"
content: {}
}
validateMessage(userMessage)
saveMessage(userMessage)
sendMessageViaEmail(userMessage)
**sendMessageViaMobilePush(userMessage)**
console.log(userMessage) // => ?
and now answer some questions:
what is under userMessage on line sendMessageViaMobilePush(userMessage)) in mutable code?
{
id: "xxx-xxx-xxx-xxx", //set by ..(Answer for question 3)
user:"John Tribe", //set by sendMessageViaEmail
topic: "Email title", //set by sendMessageViaEmail
status: FINAL, //set by saveMessage or could be set by sendMessageViaEmail
from: "..", //set by sendMessageViaEmail
to:"...", //set by sendMessageViaEmail
valid:true, //set by validateMessage
state: SENT //set by sendMessageViaEmail
}
Surprised?? Me too :d. But this is normal with mutability in javascript.
(in Java too but a bit in different way. When You expect null but get some object).
What is under userMessage on same line in immutable code?
const userMessage = {
user: "userId",
topic: "topicId",
content: {}
}
Easy right ?
Can You guess by which method "id" is updated in mutable code in Snippet 1 ??
By sendMessageViaEmail.
Why?
Why not?
Well it was at first updated by saveMessage,
but then overridden by sendMessageViaEmail.
In mutable code people didn't received push messages (sendMessageViaMobilePush). Can You guess why ??
because I am amazing developer :D and I put safety check in method sendMessageViaMobilePush(userMessage)
function sendMessageViaMobilePush(userMessage) {
if (userMessage.state != SENT) { //was set to SENT by sendMessageViaEmail
send(userMessage)
}
}
Even if You saw this method before,
was this possible for You to predict this behavior in mutable code ?
For me it wasn't.
Hope this helped You to understand what is major issue using mutable objects in javascript.
Note that when complexity rise it is too difficult to check what was set and where especially when You work with other people.
I've created a framework agnostic open source (MIT) lib for mutable (or immutable) state which can replace all those immutable storage like libs (redux, vuex etc...).
Immutable states was ugly for me because there was too much work to do (a lot of actions for simple read/write operations), code was less readable and performance for big datasets was not acceptable (whole component re-render :/ ).
With deep-state-observer I can update only one node with dot notation and use wildcards. I can also create history of the state (undo/redo/time travel) keeping just those concrete values that have been changed {path:value} = less memory usage.
With deep-state-observer I can fine-tune things and I have grain control over component behavior so performance can be drastically improved. Code is more readable and refactoring is a lot easier - just search and replace path strings (no need to change code/logic).
The main advantage of immutability is its simplicity.
Replacing an object is simpler than modifying an existing one.
It allows you to focus on correctness in one place. Rather than every possible place where your object might change.
If your object is in an invalid state, its easier to fix because the fault must have occurred when you created it (since its immutable)
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.
// this function will change the letter in all the array
function fillWithZ(arr) {
for (var i = 0; i < arr.length; ++i) {
if (i === 4) // rare condition
return arr; // some error here
arr[i] = "Z";
}
return arr;
}
console.log(fillWithZ(["A","A","A"])) // ok, valid state
console.log(fillWithZ(["A","A","A","A","A","A"])) // bad, invalid state
if arr become an immutable object, then we will be sure arr is always in a valid state.
Related
There are a couple rules that are arguably good to follow when writing code:
Code is easier to read and reason about when there's no reassignment; many linters recommend preferring const whenever possible.
Code is also easier to read and reason about when objects do not get mutated. If you define an object in one part of the code, it's helpful to know that you may freely reference that object elsewhere, and it will be exactly the same.
In most cases, these rules are just fine, and both of them can be followed without issue. But is it possible to follow them both when implementing a module which has both setter and getter functionality (which is a very common pattern in programming)? For example:
const module = (() => {
// Reassignment, but no mutation:
let savedData;
return {
getData: () => savedData,
setData: (newData) => savedData = newData
};
})();
module.setData('foo');
console.log(module.getData());
const module = (() => {
// Mutation, but no reassignment:
const savedData = { theKey: null };
return {
getData: () => savedData.theKey,
setData: (newData) => savedData.theKey = newData
};
})();
module.setData('foo');
console.log(module.getData());
I can't think of how one could possibly implement something like this without either mutating or reassigning somewhere - but such things should be avoided. Is what I'm looking for possible, or is it simply a fact of life that I must choose one or the other, and I should just shrug and pick one?
If I called the module with the data to set it with initially, and never set its data again, it would be possible, but this approach is very inflexible and will not fulfill most useful use-cases.
const makeDataHolder = (savedData) => {
return {
getData: () => savedData,
};
};
const fooData = makeDataHolder('foo');
console.log(fooData.getData());
I'm not necessarily looking for a solution that follows all the principles of functional programming (though, if one exists, it'd be interesting to see), but this general problem is probably familiar to those who use functional programming.
First of all, the duality you're observing between mutation and reassignment is completely correct. Implementing something with a mutable data structure is equally doable by using an immutable structure, but reassigning it every time.
Now, there is one important point to keep in mind: functional programming cannot magically remove the need for mutation. What it can do, however, is move the mutation to the boundaries of the codebase, hence keeping the code itself clean and mutation-free.
One example of "pushing the mutation away from the code" is using a database. Databases are inherently mutable, and that's fine. Nobody has a problem with databases being mutable, and nobody claims that databases shouldn't be used in functional programming. It's OK as long as the mutability is kept in the database only, and the code dealing with the database doesn't include any mutations on its own. If you don't want to keep your data in some database storage, but in memory (e.g. for performance reasons), you can use an in-memory store like Redis and still have your code mutation-free. Again, as long as you keep the reassignment and mutation out of the codebase itself, you are adhering to the principles of functional programming.
It helps to look at a program as some processing unit which has I/O on the "edge", which brings data from the producers and takes the processed data to the consumers:
There's no reason why your program needs to mutate anything on its own. It takes some data from the input side, processes it and sends it to the output side. This procedure can be intertwined, of course; for example, during the processing of the input, every once in a while something gets sent to the log, which is the output. The point is, all mutation happens on the "edge" (writing to database / log / filesystem, sending http requests to other APIs, etc.). If you feel like your program needs a getter and a setter at some point, you either need to re-think your design, or you need to push the getter/setter functionality away to an outer layer, such as the database (setting a field is not permitted in functional programming, but updating a database record is completely fine).
Also, many programming languages don't enforce immutability, but still encourage functional programming style. Sometimes iterative way of programming and using mutable data turns out to be more performant that functional. As long as the immutability is hidden away from the rest of the program and is kept localized to that particular part of the code, it doesn't hurt that much. For example, all internal implementations of foldLeft in Scala (that I know of) are mutable. But that's not a problem, because the users of the foldLeft method have no way to access the mutable data, so the mutability is not exposed to the outside. Same goes for almost all sorting algorithms; they are implemented in mutable fashion, replacing the elements of the array in-place, but the users of these methods don't see that. The fact that the internal implementation uses mutability doesn't reduce the readability or reasoning of the code, because it's not visible in the rest of the code.
implementing a module which has both setter and getter functionality
is fundamentally at odds with:
objects do not get mutated
A "setter" (as commonly understood) is always a mutation.
However, in purely functional programming languages like Haskell, you can use a state monad, which allows you to write purely functional code that looks and feels very much like imperative code with getters and setters.
If you google it, there are also quite a few tutorials how you might implement and use a state monad in JavaScript.
In my opinion, the module here is just something like a stateful closure. Modifying the state happens to be your purpose. In lisp, set! operator is specifically introduced for this purpose. Anyway, as long as you want to maintain a state by yourself, the pure function rules will inevitably be broken.
I am using the react-redux for one of my app, The design is quite difficult and performance required is very high. its actually wyswyg builder.
We have been using the react from last 2 months, Then we moved to the react-redux for the separation of code and improve maitainance, code readability and the parent-child approach headache ofc.
So, I have an array which has quite complex structure
This is how my state look a like:
const initialState = {
builder:{},
CurrentElementName:"",
CurrentSlideName:"",
.......
}
As redux recommend to have less data in particular object as possible, I have another 8-9 reducer which are divided from the main state.
My problem: builder object is very complex which has almost 3-4 levels down, objects and arrays, this all are managed runtime.
So, on the componentdidmount my application will call the server get the data and fill the builder:{}
builder:{
slidedata:[{index:0,controName:'button',....},{index:0,controName:'slide',....}],
currentSlideName:'slide1',
currentElementName:'button1'
}
This builder object is quite complex and depends on the user actions like drag and drop, changing the property, changing events, changing position this builder object is being changed by the reducer
let clonedState= JSON.parse(JSON.stringify(state));
//doing other operations
Every time some thing changes this object needs to perform certain complex operations, for ex, adding the new slide will do certain operations and add the slide to the current array called slidedata.
What is the best practice to fast this things up? am I doing something wrong?
I am not sure what is the wrong in this code, and as redux recommend I can not use the flat structure for this particular array as its managed run-time.
I am sure that component has the data which the component wants.
Is there any way to handle the big data? This iterations and changing the state is killing my performance.
Based on my current experience with React-Redux framework, Re-select and ImmutableJS make a perfect combination for your requirement.
Re-Select uses memoization technique on Javascript objects and have list of API's specifically dealing with these kind of large set of Javascript objects thus improving performance. Read the docs.
Note: One should wisely read the documentation before using this setup to churn the best of these tools.
You can either create your own boilerplate code using above libraries or use the one which i am currently using in my project.
https://www.reactboilerplate.com/
This boilerplate is specifically designed for performance. You can customize it based on your needs.
Hope this helps!
I'm building an app with React/Redux that is in some ways similar to a text editor. It's not a text editor exactly, but it's the same general paradigm. There is a cursor for placing new items. Items can be added, selected, deleted, etc.
I'm struggling with the best way to structure my reducers in a way that is in keeping with the spirit of redux. I have separate state slices representing the selection state, the text itself, the cursor state, and other settings. I think the "redux" approach would be to have reducers for each of these state slices, independently mutating state in response to an action.
However, in a text editor these state slices are a lot more coupled than at first glance. When you press a key, sometimes a letter will be added at the location of the cursor, and the cursor will move forward. If text is selected, however, the selected text will be deleted first. If you are in "insert" mode, text to the right will be "consumed". Or maybe a modifier key was down, and text isn't added at all.
In other words, the different state slices are very coupled and what happens in one depends on the current state of the others.
I've read the "Beyond Combine Reducers" section in the Redux manual and know how to share state between slice reducers, but this seems inelegant if the end result is passing the entire state to every slice reducer. The other thing I don't like about his approach is that each reducer would have to look at the overall state and independently come to the same conclusion about what its correct response to a particular action should be. Is that what I should be doing or I should be structuring my state differently somehow?
The alternative of one centralized reducer telling the cursor, the selection state, the content, etc. how to mutate is easier conceptually but doesn't seem to scale well.
I've also read that many times coupled state is a sign that your state isn't minimal and that you should be restructuring and using memoized selectors. However that doesn't seem to be the case here. The position of the cursor is not derivable from the text, nor is the selection state.
Lastly, I've also considered Thunk middleware as this is something that I've seen suggested for handling multiple/more complex actions. I'm hesitant because it seems like it is more meant for asynchronous dispatch and this is not that.
I'd like to understand the correct approach for designing this type of app that is most in keeping with the "redux" design pattern and understand any tradeoffs there might be if there are multiple ways forward.
I wrote that "Structuring Reducers" doc section, so nice to see that people are at least reading it and finding it useful :)
You're right that the idiomatic intended approach for Redux reducer logic is small reducer functions, organized by slice of state, independently responding to the same actions. However, that's not a fixed requirement, and there are definitely times when it makes more sense to consolidate some of the logic into one place.
It's a bit hard to give absolute specific advice without seeing what your state structure is and exactly what problems you're trying to solve, but overall, you should feel free to structure your state and your reducer logic in whatever way makes the most sense for your application. If it works better to have some of that logic in a more centralized reducer function that updates several nested pieces of state at once, go for it!
As a couple other observations:
Per the Redux FAQ question on "sharing state across reducers", one approach is to put more information into the dispatched action. For example, rather than dispatching {type : "KEYSTROKE", key : "A"}, you could dispatch {type : "KEYSTROKE", key : "A", cursorPos : 12345, ctrl : true, alt : false}.
Also, while thunks are a good place for basic async logic, they are also useful for complex synchronous logic as well, including inspecting the current app state. I have a gist that demonstrates some common thunk use cases.
Lemme toss out a couple more resources that may be of general assistance to you:
My React/Redux links list has a section linking to articles on writing reducers
My "Practical Redux" tutorial series demonstrates a few variations on reducer structures, including the post Practical Redux, Part 7: Form Change Handling, Data Editing, and Feature Reducers.
(As a side note, I'm also currently working on a blog post that will discuss what actual technical limitations Redux requires and why, vs how you are "intended" to use Redux, vs how it's possible to use Redux. Will take me a while to finish it, but keep an eye on my blog if you're interested.)
Finally, if you'd like to discuss things further, the Reactiflux chat channels on Discord are a great place to hang out, ask questions, and learn. The invite link is at https://www.reactiflux.com . Please feel free to drop by there and ask questions - I'm usually on there evenings US time, but there's always a bunch of people hanging out happy to discuss things.
Seems you are taking a huge task; probably you already know that, but creating a text editor from scratch is not an easy task.
Did you evaluated using an existing software?
Recently I used with success the super powerful Codemirror and integrated it with a React.js application. Codemirror already manage the concept of state of the document in a great way.
That means:
Codemirror instance fully manage the editor (AKA: the document)
React environment is attached to the document through callbacks and events.
If Codemirror doesn't fit your needs, take a look at it's code and internals description.
So I started learning React a week ago and I inevitably got to the problem of state and how components are supposed to communicate with the rest of the app. I searched around and Redux seems to be the flavor of the month. I read through all the documentation and I think it's actually a pretty revolutionary idea. Here are my thoughts on it:
State is generally agreed to be pretty evil and a large source of bugs in programming. Instead of scattering it all throughout your app Redux says why not just have it all concentrated in a global state tree that you have to emit actions to change? Sounds interesting. All programs need state so let's stick it in one impure space and only modify it from within there so bugs are easy to track down. Then we can also declaratively bind individual state pieces to React components and have them auto-redraw and everything is beautiful.
However, I have two questions about this whole design. For one, why does the state tree need to be immutable? Say I don't care about time travel debugging, hot reload, and have already implemented undo/redo in my app. It just seems so cumbersome to have to do this:
case COMPLETE_TODO:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
];
Instead of this:
case COMPLETE_TODO:
state[action.index].completed = true;
Not to mention I am making an online whiteboard just to learn and every state change might be as simple as adding a brush stroke to the command list. After a while (hundreds of brush strokes) duplicating this entire array might start becoming extremely expensive and time-consuming.
I'm ok with a global state tree that is independent from the UI that is mutated via actions, but does it really need to be immutable? What's wrong with a simple implementation like this (very rough draft. wrote in 1 minute)?
var store = { items: [] };
export function getState() {
return store;
}
export function addTodo(text) {
store.items.push({ "text": text, "completed", false});
}
export function completeTodo(index) {
store.items[index].completed = true;
}
It's still a global state tree mutated via actions emitted but extremely simple and efficient.
Isn't Redux just glorified global state?
Of course it is. But the same holds for every database you have ever used. It is better to treat Redux as an in-memory database - which your components can reactively depend upon.
Immutability enables checking if any sub-tree has been altered very efficient because it simplifies down to an identity check.
Yes, your implementation is efficient, but the entire virtual dom will have to be re-rendered each time the tree is manipulated somehow.
If you are using React, it will eventually do a diff against the actual dom and perform minimal batch-optimized manipulations, but the full top-down re-rendering is still inefficient.
For an immutable tree, stateless components just have to check if the subtree(s) it depends on, differ in identities compared to previous value(s), and if so - the rendering can be avoided entirely.
Yes it is!!!
Since there is no governance of who is allowed to write a specific property/variable/entry to the store and practically you can dispatch any action from anywhere, the code tends to be harder to maintain and even spaghetti when your code base grows and/or managed by more than one person.
I had the same questions and issues with Redux when I started use it so I have created a library that fix these issue:
It is called Yassi:
Yassi solves the problems you mentioned by define a globally readable and privately writable store. It means that anyone can read a property from the store (such as in Redux but simpler).
However only the owner of the property, meaning the object that declare the property can write/update that property in the store
In addition, Yassi has other perks in it such as zero boilerplate to declare entry in the store by using annotations (use #yassit('someName'))
Update the value of that entry does not require actions/reducers or other such cumbersome code snippets, instead just update the variable like in regular object.
Imagine a situation that John have two childrens Alice and Bob, and Bob have a cat Orion.
var Immutable = require('immutable');
var parent = Immutable.Map({name: 'John'});
var childrens = Immutable.List([
Immutable.Map({name: 'Alice', parent: parent}),
Immutable.Map({name: 'Bob', parent: parent})
]);
var cat = Immutable.Map({name: 'Orion', owner: childrens.get(1)});
After few years John wants to rename to Jane.
var renamedParent = parent.set('name', 'Jane');
...and let childrens know about it.
childrens = childrens.map(function(children) {
children.set('parent', renamedParent);
});
Then I have to update cat because Bob changed.
cat = cat.set('owner', childrens.get(1));
Is it possible to automatically update all related objects when one object change? I looked at Cursors, but I'm not sure if they are a solution. If it possible, can you give me an example?
Paraphrasing the question:
Is it possible to automatically update all related objects when one object changes in an immutable collection?
Short answer
No.
Long answer
No, but nothing ever changes in an immutable data structure so that's not a problem.
Even longer answer
It's more complicated...
Immutability
The whole point of immutable objects is that if you have a reference to an immutable object you don't ever have to bother checking whether any of its properties have changed. So, is it a non-issue? Well...
Consequences
There are some consequences of that - whether they are good or bad depends on your expectations:
There is no difference between pass-by-value and pass-by-reference semantics
Some comparisons can be easier
When you pass a reference to an object somewhere you don't have to worry that some other part of code will change it
When you get a reference to an object from somewhere you know it will never change
You avoid some problems with concurrency because there is no notion of a change in time
When nothing ever changes you don't have to worry whether changes are atomic
It's easier to implement software transactional memory (STM) with immutable data structures
But the world is mutable
Of course in practice we often deal with values that change in time. It may seem that immutable state can't describe mutable world but there are some ways people deal with it.
Look at it this way: if you have your address on some ID and you move to a different address, that ID should be changed to be consistent with new true data, because it is no longer true that you live at that address. But when you get an invoice when you buy something which contains your address and then you change your address, the invoice stays the same because it is still true that you lived at that address when the invoice was written. Some data representations in the real world are immutable, like invoices in that example, and some are mutable like IDs.
Now taking your example, if you choose to use immutable structures to model your data, you have to think about it in a way that you think about the invoice from my example. It may be true that the data is not up to date but it will always be consistent and true for some point in time, and it will never change.
How to deal with change
So how to model change with immutable data? There is a nice way it has been solved in Clojure using Vars, Refs, Atoms, and Agents, and ClojureScript (a compiler for Clojure that targets JavaScript) supports some of them (in particular Atoms are supposed to work as in Clojure but there are no Refs, STM, Vars or Agents - see what are the differences between ClojureScript and Clojure regarding concurrency features).
Looking at how Atoms are implemented in ClojureScript it seems that you can just use ordinary JavaScript objects to achieve the same. It will work for things like having a JavaScript object that is itself mutable, but it has a property that is a reference to an immutable object - you will not be able to change any properties of that immutable object, but you will be able to construct a different immutable object, and swap the old one to the new one in your top-level mutable object.
Other languages like Haskell that are purely functional may have different ways to deal with mutable world, like monads (a concept notoriously hard to explain - Douglas Crockford, author of JavaScript: The Good Parts and discoverer of JSON attributes it to "the monadic curse" in his talk Monads and Gonads).
Your question seems simple but the problem it touches is actually quite complicated. Of course it would be missing the point to just answer "No" to your question whether it is possible to automatically update all related objects when one object changes, but it is more complicated than that, and saying that in immutable objects nothing ever changes (so this problem never happens) will be equally unhelpful.
Possible solutions
You can have a top level object or variable from which you always access all your structures. Let's say you have:
var data = { value: Immutable.Map({...}) }
If you always access your data using data.value (or with some better names) then you can pass the data to some other part of your code, and whenever your state changes you can just assign a new Immutable.Map({...}) to your data.value and at that point all your code that uses data will get fresh values.
How and when to update the data.value to a new immutable structure could be solved by making it automatically triggered from your setter functions that you would use to update your state.
Another way would be to use similar tricks at the level of every structure, for example - I use the original spelling of the variables:
var parent = {data: Immutable.Map({name: 'John'}) };
var childrens = {data: Immutable.List([
Immutable.Map({name: 'Alice', parent: parent}),
Immutable.Map({name: 'Bob', parent: parent})
])};
but then you have to remember that what you have as values are not immutable structures but rather those additional objects with references to immutable structures that introduce an additional level of indirection.
Some reading
What I would suggest is to look at some of those projects and articles:
Immutable React article by Peter Hausel
Morearty.js - using immutable state in React like in Om but written in pure JavaScript
react-cursor - functional state management abstraction for use with Facebook
Omniscient - a library providing an abstraction for React components that allows for fast top-down rendering embracing immutable data
* Om - ClojureScript interface to React
mori - a library for using ClojureScript's persistent data structures in JavaScript
Fluxy - an implementation of Facebook's Flux archtecture
Facebook's Immutable - persistent data collections for JavaScript that when combined with Facebook React and Facebook Flux faces similar problems that you have (searching for how to combine Immutable with React and Flux may give you some good ideas)
I hope this answer even if not giving a simple solution will nevertheless be helpful, because describing mutable world with immutable structures is a very interesting and important problem.
Other approaches
For a different approach to immutability, with immutable objects that are proxies to data that is not necessarily constant, see the Immutable Objects vs. Common Sense webinar by Yegor Bugayenko and his articles:
Objects Should Be Immutable
How Immutability Helps
How an Immutable Object Can Have State and Behavior?
Immutable Objects Are Not Dumb
Yegor Bugayenko uses the term "immutable" in a slightly different sense than what it usually means in the context of functional programming. Instead of using immutable or persistent data structures and functional programming, he advocates the use of object oriented programming in the original sense of the term in a way that you never actually mutate any object but you can ask it to change some state, or mutate some data, that is itself considered to be separate from the object. It's easy to imagine an immutable object that talks to a relational database. The object itself can be immutable but it can still update the data stored in the database. It's somewhat harder to imagine that some data stored in RAM can be thought of as equally separate from the object as the data in the database but there is really not much difference. If you think about objects as autonomous entities that expose some behavior and you respect their abstraction boundaries then it actually makes a lot of sense to think about objects as something different than just data and then you can have immutable objects with mutable data.
Please comment if anything needs some clarification.
As rsp clarified, this problem reflects the inherent trade-off offered by immutability.
Here's an example react/flux-ish app demonstrating one way to deal with this problem. The key here is that numeric IDs are used for reference rather than Javascript references.
From what I understand, you might be using immutable objects a bit too high level. As far as I know immutable objects are useful to represent time-captured states. So it's easy to compare state1 === state2. In your example however, you have also time-captured relationships in the state. Which is fine to compare the complete state with another complete state, because it's unchanging data so it's very readable, but therefor also hardly updatable. I suggest before you add another library to fix this problem, try and see if you can implement Immutable at a lower level, where you actually NEED to compare time-captured states. For example, to know whether 1 entity (person/cat) changed.
So where you do want to use immutable objects, use them. But if you want dynamic objects, don't use immutable objects.
It might be that this situation can be solved by using ids to reference the parents rather than parent records themselves. I'm looking to SQL (sorta) for guidance here: A record should not have a pointer to another record in memory, but rather should know the id of the other record.
In my apps I like having each object only know the primary keys of its reference objects so I don't have to worry about questions like what if an object changes. As long as its key stays the same (as it should) I can always find it:
var Immutable = require('immutable');
var people = Immutable.OrderedMap({
0: Immutable.Map({name: 'John', id: '0'}),
1: Immutable.Map({name: 'Alice', id: '1', parentId: '0'}),
2: Immutable.Map({name: 'Bob', id: '2', parentId: '0'})
});
var cat = Immutable.Map({name: 'Orion', ownerId: '2'});
Now I can change any characteristic of any record (except the id of course) using the standard immutable.js tools without having to do any additional updating.
people = people.set('0', people.get('0').set('name', 'Jane'))
After being frustrated and getting no where with this exact same problem, I decided to move relationships out of my objects completely and manage the logic of various common associations (one-to-one, one-to-many, many-to-many) separately.
Essentially, I'm managing relationships with bi-directional maps and keeping relationship logic centralized in an object instead of in each of my modeled data as is traditionally the case. That means I needed to come up with the logic to observe, for example, when a parent has changed and propagate the changes to the child relationships (hence the bimaps). Since its abstracted in its own module however, it can be reused to model future relationships.
I decided not go with ImmutableJS for handling this, instead rolling my own library (https://github.com/jameslk/relatedjs) and using ES6 features, but I imagine it can be done in a similar way.