16 comments

[ 2.2 ms ] story [ 52.6 ms ] thread

  var array = Immutable(["totally", "immutable", {hammer: "Can’t Touch This"}]);

  array[1] = "I'm going to mutate you!"
  array[1] // "immutable"
I find it a little weird that the result of trying to mutate an immutable object is to silently fail the mutation. Couldn't this hide errors where the developer expects something to mutate because they didn't realize it was immutable? Shouldn't it throw instead?

Edit: After reading the documentation more thoroughly, I saw "All the methods that would normally mutate the data structures instead throw ImmutableError." Looks like the first section isn't actually accurate then?

(Library author here.) Unfortunately, in JavaScript it's not possible to override array element reassignment behavior. You can call Object.freeze on the array, which makes reassignment silently do nothing, but you cannot override it to throw an exception.

The reason the docs say "the methods that would normally mutate..." is that in the specific case of methods (e.g. array.push()), the library can and does override them to throw exceptions.

I would certainly prefer to make that example throw an exception, but it's simply not possible in JS. :)

Object.freeze will throw if you `'use strict';`.
Very true...I should note that in the documentation. Thanks!
Thanks for sharing that tidbit of information. I did not know that and now I do, I appreciate it!

I wonder what the reason behind that is, if you're feeling extra motivated you could even look into having a conversation with the folks who decide what future versions of JS look like to add something like it. I am a huge proponent of immutability and can see how being able to override array element assignment behaviors would improve your library.

    Object.defineProperty(x,'foo',{set:function() { throw new Error(69) }})
You can define a setter that throws in order to throw without using 'use strict;'. However, additions will still be silent :(

https://gist.github.com/vjeux/6b390e6a6bb51e24b646

    __DEV__ = true;
    var array = ['a', 'b', 'c']
    deepFreezeAndThrowOnMutationInDev(array)
    array[0] = 10;
    Error: You attempted to set the key `0` with the value `10` on an object that is meant to be immutable and has been frozen.
I spent the better part of an hour cursing about this. Chrome returns frozen objects from Web SQL. Now I didn't know that a poor language like Javascript had a Frozen! No errors! Finally found it when I queried for Angular failing to update objects because the looked immutable.
I wonder what the performance of this is. While functional languages like Haskell are optimized for these kinds of data structures, I doubt Javascript runtimes currently are. We've been bitten before by writing code in too much of a functional style and getting terrible performance, so benchmarks would be really useful before we'd start to use this.
I agree that benchmarks are the final arbiter, but javascript engines are pretty well optimized for handling garbage. So if you're going to be making garbage, javascript isn't a bad language to do it in, and immutable data structure algorithmic performance isn't going to change in js.
Haskell and Clojure both use structure-sharing data structures, which allow immutability without the cost of copying the entire structure whenever you want to make an update. They also use laziness to improve the performance of their data structures.

If you want an implementation of these ideas in JS, Immutable.js [0] or Mori [1] are the leading libraries. seamless-immutable doesn't use these techniques, so it probably wouldn't perform well on large data sets. The benefit of it is that the immutable objects can be used as drop-in replacements for their native JS equivalents in some situations.

Full disclosure: I've contributed to Immutable.js

[0] https://github.com/facebook/immutable-js

[1] https://github.com/swannodette/mori

How does this compare to https://github.com/facebook/immutable-js ? Has anybody used both?
You have to convert to and from js objects with the facebook one (immutable-js), although lots of the js api calls are the same push/set/slice etc.

This one is directly on js objects (seamless-immutable).

From what I can see, seamless-immutable basically just enforces immutability on native JavaScript data structures. Immutable.js on the other hand, implements full persistent data structures, which give much better time complexity guarantees about important operations. Immutable.js also has a rich API designed for manipulating immutable data structures and uses lazy evaluation for methods like map, filter and concat, which really improves performance when chaining chose operations.
They both mimic the standard Array/Map/Set methods but differ in how they handle mutating methods like push and set. In Facebook's version, these functions return a new immutable instance with the values changed appropriately, while this one throws an error. It also provides a few new methods to combine/transform existing immutables.

I like the look of this one better. IMHO Facebook's approach will lead to confusion and subtle errors when their immutables are mixed up with normal objects and arrays. Personally I think this is think that's an unwise decision that will lead to confusion and subtle errors.