Live data from Hacker News

Immutable.js – Immutable Data Collections

facebook.github.io

11–20 of 86 posts

Re: Immutable.js – Immutable Data Collections

#11
post #5

What is the benefit of having immutable variables that are just fake-built at runtime? At compile time, knowing some variables are constant and will not change would give the interpreter/compiler a lot of optimization chances but does this apply the same at runtime as well? the website says "efficiency" because immutable variables wouldn't need to be deep copied but would the deep copy operations be that frequent in…

The big thing is Object.freeze() which allows efficient object handling.

The trouble is that arrays must look and act like objects. Objects must look and at like hashes, and hashes are very inefficient. The solution is to implement arrays as arrays or structs and objects as structs or static classes. This sounds good, but what happens when that array changes size or a property is added to that object?

The answer is that the jit must constantly check for this behavior. If it sees this happen, it has to throw out all the optimized code it has generated and start over again (reducing performance in the meantime and using more power on mobile as well).

If the object cannot be changed, then the compiler can make more guarantees, so it can optimize sooner, more reliably, and is less likely to need to fall back to unoptimized byte code.

Re: Immutable.js – Immutable Data Collections

#13
post #6
post #5

What is the benefit of having immutable variables that are just fake-built at runtime? At compile time, knowing some variables are constant and will not change would give the interpreter/compiler a lot of optimization chances but does this apply the same at runtime as well? the website says "efficiency" because immutable variables wouldn't need to be deep copied but would the deep copy operations be that frequent in…

One benefit is that you can do simple O(1) equality comparisons in UI libraries like React to determine whether data has changed (and thus whether UI needs to be refreshed).

This doesn't necessarily work. Consider scenarios where you do one edit and then effectively undo it before the redraw. Or, more realistically, two rapidly successive edits effectively undo each other.

Also, one could just as easily keep a dirty bit oneself.

Re: Immutable.js – Immutable Data Collections

#14

> The difference for the immutable collections is that methods which would mutate the collection, like 'push', 'set', 'unshift' or 'splice' instead return a new immutable collection. I think this is an unfortunate design decision which should be reconsidered. Functional operations should have different names than side-effecting operations. In general, I think that while side-effecting operations are commonly verbs, f…

Not sure if I agree - it's more natural to have only immutable collections if taking a functional approach. Eg see scala or haskell. Does strong typing change that? It's very clear if you're whole code base has no side effects what is happening when and where.

Re: Immutable.js – Immutable Data Collections

#15
post #13
post #6

Earlier quoted context omitted.

One benefit is that you can do simple O(1) equality comparisons in UI libraries like React to determine whether data has changed (and thus whether UI needs to be refreshed).

This doesn't necessarily work. Consider scenarios where you do one edit and then effectively undo it before the redraw. Or, more realistically, two rapidly successive edits effectively undo each other. Also, one could just as easily keep a dirty bit oneself.

Yeah, that's true for O(1) === comparison. The library does also provide Immutable.is(foo, bar) which does nested value checking, but that's obviously not O(1).

Re: Immutable.js – Immutable Data Collections

#16

> The difference for the immutable collections is that methods which would mutate the collection, like 'push', 'set', 'unshift' or 'splice' instead return a new immutable collection. I think this is an unfortunate design decision which should be reconsidered. Functional operations should have different names than side-effecting operations. In general, I think that while side-effecting operations are commonly verbs, f…

I empathize with your argument that operations with significantly different behavior ought to have different names, although I think the convenience of using familiar method names might outweigh the confusion of new readers (depending on the size/scope/structure of your software project).

I'm less a fan of your argument that method names like "push" or "add" inherently imply that they mutate their caller. I see no reason for that to be the case, other than in the context of your first argument. I think that an "add" method that returns a new integer without mutating its caller accurately conveys the semantics of the operation just as much as an "add" method that mutates its caller.

Re: Immutable.js – Immutable Data Collections

#18
I've been using this (v2, though) rather extensively the last few months so I figured I'd share some experiences.

First off, it works great. The TypeScript definition file also works fine as an API documentation of sorts, although it would be nice if some web site with a clickable TOC could be generated from it.

I was a little confused at the beginning how the "Sequence" base class (changed name to Iterable in v3) was an arbitrary key=>value mapping (with no apparent relation between the keys and the ordering of the key/value pairs) that I had expected would be called "Map". The name change made this clearer for me: it's basically an abstract interface, not a concrete datastructure.

The TypeScript support, to my experience, does not work as advertised on the tin, especially when you nest data structures. For example, code like this compiles fine:

   var q = Immutable.Map>();
   q.set("hello", Immutable.List([1,2,3])); // typechecks until here
   q.updateIn(["hello", "wrong"], false); // shouldn't be possible, but is.
Similarly, if you use Immutable.Record to build immutable objects, then you can still call set() with any key because the key is a string instead of something TypeScript could typecheck. Meanwhile, using direct property access on Immutable.Records, like this, will fail:

    var Banana = Immutable.Record({length: 0, colour: "yellow"});
    var someBanana = new Banana();
    someBanana.curve = 5.0;         // should fail, but doesn't
    console.log(someBanana.length); // fails, but shouldn't
The last line will fail to compile in TypeScript even though it works in Immutable.js. I managed to write a wrapper for Immutable.Record() that "solves" this, but at the cost of highly verbose repetition for each record class.

I tried very hard to "fix" this, and I have become aware that this is nearly entirely due to limitations of TypeScript's very poor generics support. It really couldn't be any better than it is. But still, the front page claims great TypeScript support and I'd say it's half-assed at best.

I chose Immutable.js over Mori because I think the API is slightly less verbose and more JavaScript-ish. I think this is mostly a matter of taste.

I found that I kept forgetting the names of methods, or being unsure about their exact signatures. Also, I often use plain JS datastructures in "little" parts of the code (stuff that doesn't persist cross function calls), I use LoDash and ES5 built-ins to manipulate those, and these functions all have subtly different names and semantics again. I suspect that very few codebases won't do this in practice: mix Immutable.js data structures with native JS data structures all over the place, and a need to manipulate both here and there.

I think transducers may be an opportunity there. Our very own jlongster has a nice writeup [1] of how they enable you to use the exact same data manipulation syntax for both native JS data structures and Immutable.js collections at no performance cost. I think that maybe Immutable.js should embrace this and release an alternative build of the library that has absolutely no manipulation functions except the hooks that transducers need to consume and produce Immutable.js collections.

Finally, I've been doubting whether Immutable.Record is worth the hassle. Maybe a single function that can easily clone a JS object but change 1 field is more than good enough. For example, with lodash/underscore this function would be a oneliner like:

    var newRecord = _.merge({}, oldRecord, {someKey: newValue});
(there might be a "shorter" way, I find the underscore API horribly obtuse and difficult to figure out, but that's not the point here)

The biggest disadvantage of using vanilla JS objects over Immutable.Record is that you're not sure that it'll not mutate if you forget to Object.freeze. I doubt many record-type objects have so many fields that cloning them has a larger performance overhead than Immutable.js's internals. I'm curious what other people's ideas and experiences are here.

[1] http://jlongster.com/Transducers.js--A-JavaScript-Library-fo...

Post reply on HN