
Immutable Data Structures That Are Compatible with Normal JS Arrays and Objects - kasbah
https://github.com/rtfeldman/seamless-immutable
======
acemarke
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].

[0] [https://github.com/markerikson/redux-ecosystem-
links/blob/ma...](https://github.com/markerikson/redux-ecosystem-
links/blob/master/immutable-data.md)

[1] [https://github.com/markerikson/redux-ecosystem-
links/blob/ma...](https://github.com/markerikson/redux-ecosystem-
links/blob/master/devtools.md#linting)

~~~
hex13
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](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:

    
    
        const copy = transform(original, stage => {
            stage.x = 10;
            stage.y = 20;
            stage.foo.bar = 123;
        })
    

instead of Object.assign / ... mess.

~~~
coltonv
This is a neat idea, hadn't thought of this but it could definitely help me
bring new developers into the immutable style more easily.

The only issue with it is, of course, the fact that Proxies are ES6 and
everyone still has to deal with old browsers.

I know MobX does similar object observation, and they support IE, but I've
never had the time to go into their codebase. Do you know if something like
this could be written in a way that allows IE10/11 to support it?

Also, could you elaborate on why it's necessary to use a proxy at all, when in
reality you could just do a copy of the object from the very beginning and
allow them to do mutations on that?

~~~
acemarke
As far as I know, proxies simply will not work in environments that do not
support ES6, because they require purpose-built JS engine support (see some
comments at [0] as examples).

MobX works by wrapping plain objects and arrays with its "observable"
equivalents. Per [1] , its object support requires fields to already exist, so
it knows how to generate wrapper fields accordingly.

As for copying: as I talked about in the "Immutable Update Patterns" section
of the Redux docs [2], proper immutable updates require copies of _every_
level of nesting that is being modified. If you want to make an update to
`state.a.b.c.d`, you need to make copies of c, b, a, and state. That's doable,
but takes work, and can get ugly if you're dealing with nesting by hand. This
does lead to frequent mistakes, like assuming that `let newObj = oldObj` makes
a copy (it just adds another reference to the same object), or that
`Object.assign()` does deep copies (it's only shallow, ie, the first level).
It's one of the most common pain points I see for people learning immutability
and/or using Redux.

What something like the `transmutable` lib appears to give you is the ability
to write perfectly standard imperative mutation code with no extra fluff
necessary, even for nested data, and still get proper immutable updates. I'm
definitely going to have to play around with it.

[0] [https://stackoverflow.com/questions/35025204/javascript-
prox...](https://stackoverflow.com/questions/35025204/javascript-proxy-
support-in-babel)

[1]
[https://mobx.js.org/refguide/object.html](https://mobx.js.org/refguide/object.html)

[2]
[http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePat...](http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html)

~~~
hex13
on the beginning I used getters/setters but I switched to Proxy because it
allowed for simpler implementation and more flexibility.

I may consider to switch back into getters/setters, if support of Proxy is
really a problem (although getters/setters have its limitations).

There is also Proxy polyfill, although it has the same limitations
getters/setters have ("properties you want to proxy must be known at creation
time"): [https://github.com/GoogleChrome/proxy-
polyfill](https://github.com/GoogleChrome/proxy-polyfill)

------
setzer22
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.

~~~
Rotareti
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:

    
    
        my_list = [1,2,3] # mutable
        my_tuple = (1,2,3) # immutable
        my_clsobj = myclass(foo=1, bar=2)  # mutable
        my_namedt = mynamedt(foo=1, bar=2) # immutable
    
        my_list[0] # 1
        my_tuple[0] # 1
        my_clsobj.foo # 1
        my_namedt.foo # 1

------
Y7ZCQtNo39
I've been using this:

[https://github.com/guigrpa/timm](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
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.

~~~
Y7ZCQtNo39
It doesn't defeat the purpose. It only mutates if there is actually a change
to the data structure. When used properly, timm works great.

The (potential) problem is that it is still possible to mutate objects without
the use of timm's utility functions.

If you value the performance benefits (no penalty for freezing objects since
timm doesn't do that), and understand that to get the benefits, you must only
mutate objects using timm, choose timm.

If you value the additional safety other libraries provide, then absolutely
use one of those. It all depends on the use case.

You don't need to freeze objects if you are doing it properly. You could even
do static analysis to know (by checking to see if you're reassigning object
properties, etc).

------
tekkk
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.

------
tommoor
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.

~~~
kasbah
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?

~~~
acemarke
I wrote a long Reddit comment a while back that describes the reasons why I
advise that people _not_ use Immutable.js [0].

As a quick summary:

\- It doesn't magically improve perf the way some people think it will. It
does make easier to use the standard shallow equality implementation of
`shouldComponentUpdate`, and can be faster at copying/updating very large
objects. However, many people use `toJS()` to extract values, and that is
absolutely bad for perf (especially if you call it in `mapState`).

\- You either have to use its API everywhere in your codebase, or spend a lot
of time encapsulating it to keep your components unaware of its existence.

\- It can be harder to debug the contents of the objects.

I'm not sure about specific downsides for using Seamless-Immutable.

My React/Redux links list has a section of articles that discuss the pros and
cons of using Immutable.js for performance [1]. I've also got a section on use
of immutable data in general [2], including some articles that talk about how
to actually use Immutable.js in your app, and articles on using plain JS data
immutably.

[0]
[https://www.reddit.com/r/javascript/comments/4rcqpx/dan_abra...](https://www.reddit.com/r/javascript/comments/4rcqpx/dan_abramov_redux_is_not_an_architecture_or/d51g4k4/?context=3)

[1] [https://github.com/markerikson/react-redux-
links/blob/master...](https://github.com/markerikson/react-redux-
links/blob/master/react-performance.md#immutable-data)

[2] [https://github.com/markerikson/react-redux-
links/blob/master...](https://github.com/markerikson/react-redux-
links/blob/master/immutable-data.md)

~~~
kasbah
You don't appear to be actually responding to my question but are giving
unsolicited advice and plugging your projects :/

~~~
acemarke
I actually misread your question a bit at first - I originally thought you
were asking about switching _to_ Immutable.js, not away from it. I realized
that before I posted it, and decided my answer was still relevant to the
aspect of "why someone might want to switch away from Immutable.js". So, in
that sense it's adding context to the reasoning behind your question.

As I said, I'm not aware of specific downsides to using Seamless-Immutable. It
seems like a good balance of enforced immutability in development via freezing
and replacement of mutation methods, and compatibility with standard JS
object/array notation and usage.

------
vbezhenar
Modern JavaScript is full of syntax sugar but lacks operator overloading which
would be really useful for custom data structures. This surprising me.

------
SirensOfTitan
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).

~~~
zdragnar
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

------
dsun180
This looks great. Do you know the exact reason why ie10/11 is not supported?

~~~
kasbah
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.

------
iorekz
Is there perf gain when comparing 2 immutable obj deeply with === ?

~~~
acemarke
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.

------
kasbah
seamless-immutable-diff and seamless-immutable-cursor look like neat add ons
for this.

[https://github.com/micnews/seamless-immutable-
diff](https://github.com/micnews/seamless-immutable-diff)

[https://github.com/MartinSnyder/seamless-immutable-
cursor](https://github.com/MartinSnyder/seamless-immutable-cursor)

------
deegles
Any good primers on why it's beneficial to use immutables in JS? (especially
with server side dev)

~~~
pault
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.

~~~
acemarke
To add a bit more context: React itself doesn't care about mutations in terms
of re-rendering and virtual DOM diffing. In fact, it doesn't even care about
mutations in terms of calling `setState()`. I'll recap a couple previous
comments of mine at
[https://news.ycombinator.com/item?id=14706862](https://news.ycombinator.com/item?id=14706862).

You can mutate a component's state and then call `setState()`, and React will
still update the component as you'd generally expect. For React, immutability
primarily relates to implementing `shouldComponentUpdate` using the standard
shallow equality comparison approach for the best performance, and general use
of Functional Programming principles for avoiding side effects. For Redux,
immutability matters for ensuring that reducer functions are pure with no side
effects, as that is a requirement for time travel debugging and proper updates
of Redux-connected components.

So, overall immutability is definitely an encouraged approach in the
React/Redux ecosystem, and there's specific places where that immutability is
important for desired behavior.

