There's generally three categories of immutable data libraries for JS:
- Purpose-built specialized data structures (Immutable.js, Mori)
- Libraries that use freezing in some way
- Utilities that abstract over immutably updating plain JS objects and arrays.
seamless-immutable falls into the second category. Looks like it also adds some extra methods to objects it wraps/returns, and overwrites mutating methods to throw errors to help you avoid them.
My Redux addons catalog has a large page listing all of the libs I've seen that fall into these categories [0]. If you don't want to use one of the specialized data structure libs or libs that do freezing, there's at least a couple dozen immutable update utility libs out there, with a variety of APIs to choose from.
My list also has a section of Redux middlewares that will help debug accidental mutations in development, either via freezing or other comparisons [1].
I've build a library Transmutable which falls into the third category :)
it allows to use immutable data structures in mutable-like way, using plain assignments:
https://www.npmjs.com/package/transmutable
(mutations are not performed but they are just recorded in ES6 Proxy, and object is cloned on commit (sort of copy-on-write), and mutations are then applied).
There is a huge loss in usefulness for immutable objects when immutability is not a default and you have that many different implementations.
The thing I like about immutability in languages that implement it by design is that you know that if you get an data structure, it is immutable. In the world of javascript, you not only have to worry about whether an object you get from a library is immutable, but which kind of immutable implementation is using. Moreover, that information is not easily available in the type signatures, so you have to go to the library author's documentation, if any! That, to me, is a complete mess.
I totally agree with you. I wish we had a built-in immutable array type and a built-in immutable object type. I love the way it's done in Python, where you have Lists vs Tuples and Class Objects vs NamedTuples. You can consume them the same way:
The onus is on the developer to actually ensure immutability, but as long you're always mutating via the library functions, you should be fine.
I've used more serious solutions, like Immutable.js, but I prefer this instead. The wrapper functions in Immutable.js, in my experience, aren't worth the trouble.
Well if the onus is on the developer it kind of defeats the purpose no? As you likely know seemless-immutable also has a "production" mode that has better performance but doesn't ensure it. That seems like a good compromise to me, so that at least during development you get errors when things are being mutated.
The benchmarks in the Timm readme are interesting though. I would like to see a benchmark of seamless-immutable in production mode added to compare.
Nice! I will try it out as soon as I can but if it rids me of Immutable.js I will be so happy. Its API is so convoluted and you have to use .toJS() all the time since using get() is so clunky and while transforming value back to JS it will fail if it was undefined. Many small things that succeed in killing the joy of immutability for me. (But mostly the huge API that requires way too much studying)
Just a quick question is there a helper library for connecting immutable redux-store to localStorage? That is something I dearly miss if there is none although you could write one yourself I guess.
There is also no chaining of method calls or withMutations equivalent. Granted for small stuff not that important but it would be nice to have them in toolbox if use case arises.
But thanks. Immutability in JS is such a pain which will hopefully change in the future. Until then I'm looking for the next best thing.
I've been using this library for over a year, I'd say if you have an existing project that you'd like to use Immutable objects in then it's a great choice with minimal downsides. For a greenfield project Immutable.js is probably a better bet as the newer data structures come with a lot of benefits.
With something like ImmutableJS or Mori, or any other persistent data structure library that doesn't use native JS objects, there's just a lot of general friction during development that can seriously slow down both developer productivity (dealing with interop, losing access to object destructuring, spread, being limited to data access/mutation APIs provided by the libraries, difficulty in debugging, etc) and actual app performance (converting to or from JS is often expensive and can completely negate the perf benefits of the persistent data structures when overused in the wrong places, and it's extremely easy to overuse it in the wrong places if you're not familiar with React/Redux's inner workings).
If you manage to avoid all performance pitfalls and can accept some degree of loss in dev productivity, then the performance benefits from structural sharing and laziness can still be worthwhile for a sufficiently data-heavy app. For most other cases it's a very costly premature optimization though.
Until native JS persistent data structures get implemented and gain widespread support, I think something like seamless-immutable might be a reasonable compromise.
I have just started a React-Redux project using Immutable.js and am considering switching it over to this as I can see a lot of advantages in the compatibility with JS data. What downsides do you think I would encounter after switching?
Does `Object.freeze` still incur a performance penalty? Static enforcement of immutability is possible today for array types using something like `$ReadOnlyArray` tagging in flow, if a bit clunky.
I think a light wrapper that:
1. Integrated into flow and typescript.
2. Rewrote mutable methods like push/splice as immutable.
... would be sufficient for many needs. I love Immutable, but it does incur a performance penalty for the expressiveness (as far as I know), and works best when starting a new project over integrating into existing (where to/from array becomes more of an issue).
Most libraries have flags for an environment variable to skip freezing in "production" mode; any decent minifier will remove the conditions since they can't be reached, so there's no performance penalty.
Tcomb does this, and is far and away one of my favorite JS libraries for all of the other features it provides as a result.
Edit: to be clear, tcomb provides runtime types, algebraic data concepts, pattern matching, validation, and with plugins react form generation and other things. Immutability is a simple consequence of needing to guarantee a valid value stays valid; it's not so much a "feature" per se
I believe it actually supports IE9+ but the tests are currently failing so they are marked red in the test array. I suspect that they are only failing for the development branch and everything works with IE9+ if you use the latest release.
A `===` comparison is explicitly _not_ a deep comparison. It's a reference comparison, ie, "are these two variables pointing to the same object in memory?". Under the hood, that probably is interpreted as a simple pointer comparison, which is fast and cheap. That's why it's the preferred approach for doing comparisons in cases like this. _If_ you update your data immutably, then you get the benefit of quick and simple comparisons to see if things are different.
Now, a reference comparison only tells you if the objects themselves are different. It's entirely possible to have two different objects with the same or equivalent contents, such as in @kasbah's example. Both objects have a key named `a` that has a value of 1, but the objects are different references. The overall assumption when you update data immutably and compare like this is that _if_ two objects are different references, then they _probably_ have different contents, and it's time to re-render your UI.
It appears equality checks for objects is not supported i.e.:
Immutable({a: 1}) !== Immutable({a: 1})
There is no built in equality function either [1] so that seems like that's a big advantage Immutable.js has over this. Maybe seamless-immutable-diff [2] could be a way to do it but I am not sure on the performance.
A hard part of React is determining when and what to re-render. It's one of the main things the state-management tools solve (Redux, MobX, etc).
For example, imagine the naive example where you just have a global `const store = { ... }` and all components read from it and update it. You could tell everything to re-render on any change, but that's slow. So you can then implement `shouldComponentUpdate` for each component to manually check if their dependent data changed. But that may be a lot of work where each component needs to know quite a bit about the data.
For instance, how do you check if two arrays are the same and without walking both arrays? Depending on your data, it may be as simple as comparing `item.id` of the first item in each array. But it might not be.
On the other hand, you can tell if two immutable datastructures are equal with reference equality (obj1 === obj2). If all of your components take immutable data, then you can abstract away `shouldComponentUpdate` with a reference comparison. This is what React's PureComponent does.
That's the main use-case. Not as many obvious use-cases on the server side in Javascript.
In general hand-wavy terms, it helps you write side-effect free functions; if you are operating on a data structure defined outside of a function's scope and mutate it directly, you lose reproducibility and your code becomes very difficult to test. By ensuring that the data structures are immutable, you remove one common source of unpredictable behavior. You can be confident that no matter how many times you pass a function a particular state, the resulting state will always be the same. You can do this without immutable data structures by being very careful and knowing exactly which operations mutate and which return new structures (you'll see JS devs using `Object.assign` and `Array.concat` for this purpose), but enforcing immutability with a library takes the burden off the individual developer.
One of the reasons immutable JS data structures have been gaining in popularity the last few years is the adoption of React; the virtual DOM diffing algorithm relies on a few state management methods for knowing which nodes need redrawing and the DOM won't update correctly if you directly mutate the data structures the components are using for their state. As for server-side, I can only assume it's the general trend of JS developers increasingly adopting a more functional style. One of the nice side effects (hah) of using immutables the ability to easily keep a history of state transitions and revert to a previous state if something goes wrong. This can be particularly useful when dealing with distributed systems. It's also much easier to reproduce an undesired state when debugging production issues. It's not a silver bullet but it reduces the number of heisenbugs that turn up in production.
Not sure what you mean by primer but I prefer using immutable data structures because it eases programming in a functional style. I use Redux for server-side as well as front-end projects but using Redux without immutable data structures is a PITA because you have to constantly think about whether you are mutating things or not. I have been using immutable.js a lot but the difference from standard JS data types is kind of cumbersome and can become annoying so this project looks really neat. I am looking forward to giving it a try.
[+] [-] acemarke|8 years ago|reply
- Purpose-built specialized data structures (Immutable.js, Mori)
- Libraries that use freezing in some way
- Utilities that abstract over immutably updating plain JS objects and arrays.
seamless-immutable falls into the second category. Looks like it also adds some extra methods to objects it wraps/returns, and overwrites mutating methods to throw errors to help you avoid them.
My Redux addons catalog has a large page listing all of the libs I've seen that fall into these categories [0]. If you don't want to use one of the specialized data structure libs or libs that do freezing, there's at least a couple dozen immutable update utility libs out there, with a variety of APIs to choose from.
My list also has a section of Redux middlewares that will help debug accidental mutations in development, either via freezing or other comparisons [1].
[0] https://github.com/markerikson/redux-ecosystem-links/blob/ma...
[1] https://github.com/markerikson/redux-ecosystem-links/blob/ma...
[+] [-] hex13|8 years ago|reply
it allows to use immutable data structures in mutable-like way, using plain assignments: https://www.npmjs.com/package/transmutable (mutations are not performed but they are just recorded in ES6 Proxy, and object is cloned on commit (sort of copy-on-write), and mutations are then applied).
So it basically enables for writing such things:
instead of Object.assign / ... mess.[+] [-] setzer22|8 years ago|reply
The thing I like about immutability in languages that implement it by design is that you know that if you get an data structure, it is immutable. In the world of javascript, you not only have to worry about whether an object you get from a library is immutable, but which kind of immutable implementation is using. Moreover, that information is not easily available in the type signatures, so you have to go to the library author's documentation, if any! That, to me, is a complete mess.
[+] [-] Rotareti|8 years ago|reply
[+] [-] macintux|8 years ago|reply
Behavior is so well-defined in a functional system that it's intensely frustrating dealing with any imperative/OO language.
[+] [-] Y7ZCQtNo39|8 years ago|reply
https://github.com/guigrpa/timm
The onus is on the developer to actually ensure immutability, but as long you're always mutating via the library functions, you should be fine.
I've used more serious solutions, like Immutable.js, but I prefer this instead. The wrapper functions in Immutable.js, in my experience, aren't worth the trouble.
[+] [-] kasbah|8 years ago|reply
The benchmarks in the Timm readme are interesting though. I would like to see a benchmark of seamless-immutable in production mode added to compare.
[+] [-] tekkk|8 years ago|reply
Just a quick question is there a helper library for connecting immutable redux-store to localStorage? That is something I dearly miss if there is none although you could write one yourself I guess.
There is also no chaining of method calls or withMutations equivalent. Granted for small stuff not that important but it would be nice to have them in toolbox if use case arises.
But thanks. Immutability in JS is such a pain which will hopefully change in the future. Until then I'm looking for the next best thing.
[+] [-] tommoor|8 years ago|reply
[+] [-] lewisl9029|8 years ago|reply
If you manage to avoid all performance pitfalls and can accept some degree of loss in dev productivity, then the performance benefits from structural sharing and laziness can still be worthwhile for a sufficiently data-heavy app. For most other cases it's a very costly premature optimization though.
The Redux docs actually has a very thorough document on the pros and cons of using persistent data structure libraries with Redux: http://redux.js.org/docs/recipes/UsingImmutableJS.html
I'm still hoping for native JS persistent data structures to make it into the ECMAScript spec at some point in the future. The only thing I've found so far is this: https://github.com/sebmarkbage/ecmascript-immutable-data-str...
And I'm not sure if it has gained much traction.
Until native JS persistent data structures get implemented and gain widespread support, I think something like seamless-immutable might be a reasonable compromise.
[+] [-] kasbah|8 years ago|reply
[+] [-] vbezhenar|8 years ago|reply
[+] [-] SirensOfTitan|8 years ago|reply
I think a light wrapper that:
1. Integrated into flow and typescript.
2. Rewrote mutable methods like push/splice as immutable.
... would be sufficient for many needs. I love Immutable, but it does incur a performance penalty for the expressiveness (as far as I know), and works best when starting a new project over integrating into existing (where to/from array becomes more of an issue).
[+] [-] zdragnar|8 years ago|reply
Tcomb does this, and is far and away one of my favorite JS libraries for all of the other features it provides as a result.
Edit: to be clear, tcomb provides runtime types, algebraic data concepts, pattern matching, validation, and with plugins react form generation and other things. Immutability is a simple consequence of needing to guarantee a valid value stays valid; it's not so much a "feature" per se
[+] [-] dsun180|8 years ago|reply
[+] [-] kasbah|8 years ago|reply
[+] [-] filipn|8 years ago|reply
https://github.com/es-shims/es5-shim#may-fail
[+] [-] iorekz|8 years ago|reply
[+] [-] acemarke|8 years ago|reply
Now, a reference comparison only tells you if the objects themselves are different. It's entirely possible to have two different objects with the same or equivalent contents, such as in @kasbah's example. Both objects have a key named `a` that has a value of 1, but the objects are different references. The overall assumption when you update data immutably and compare like this is that _if_ two objects are different references, then they _probably_ have different contents, and it's time to re-render your UI.
[+] [-] kasbah|8 years ago|reply
[1]: https://github.com/rtfeldman/seamless-immutable/issues/186 [2]: https://www.npmjs.com/package/seamless-immutable-diff
[+] [-] unknown|8 years ago|reply
[deleted]
[+] [-] kasbah|8 years ago|reply
https://github.com/micnews/seamless-immutable-diff
https://github.com/MartinSnyder/seamless-immutable-cursor
[+] [-] deegles|8 years ago|reply
[+] [-] always_good|8 years ago|reply
For example, imagine the naive example where you just have a global `const store = { ... }` and all components read from it and update it. You could tell everything to re-render on any change, but that's slow. So you can then implement `shouldComponentUpdate` for each component to manually check if their dependent data changed. But that may be a lot of work where each component needs to know quite a bit about the data.
For instance, how do you check if two arrays are the same and without walking both arrays? Depending on your data, it may be as simple as comparing `item.id` of the first item in each array. But it might not be.
On the other hand, you can tell if two immutable datastructures are equal with reference equality (obj1 === obj2). If all of your components take immutable data, then you can abstract away `shouldComponentUpdate` with a reference comparison. This is what React's PureComponent does.
That's the main use-case. Not as many obvious use-cases on the server side in Javascript.
[+] [-] pault|8 years ago|reply
One of the reasons immutable JS data structures have been gaining in popularity the last few years is the adoption of React; the virtual DOM diffing algorithm relies on a few state management methods for knowing which nodes need redrawing and the DOM won't update correctly if you directly mutate the data structures the components are using for their state. As for server-side, I can only assume it's the general trend of JS developers increasingly adopting a more functional style. One of the nice side effects (hah) of using immutables the ability to easily keep a history of state transitions and revert to a previous state if something goes wrong. This can be particularly useful when dealing with distributed systems. It's also much easier to reproduce an undesired state when debugging production issues. It's not a silver bullet but it reduces the number of heisenbugs that turn up in production.
[+] [-] kasbah|8 years ago|reply
[+] [-] tommoor|8 years ago|reply
- Clarity of code. You can't accidentally mutate data that will then be used elsewhere.
- Performance. Being able to avoid deep equality checks makes a huge difference for React in particular.