Skip to content

Instantly share code, notes, and snippets.

@carlesba
Last active November 18, 2022 13:23
Show Gist options
  • Save carlesba/f2a5f666212d86c1fdc6 to your computer and use it in GitHub Desktop.
Save carlesba/f2a5f666212d86c1fdc6 to your computer and use it in GitHub Desktop.
Immutable builder

Purpose

As we know, javascript can't garantee that an object has been mutated so right now the only way to garantee this didn't happen is by using other libraries (like ImmutableJS).

The problem of these libraries is they force developers to use an specific interface so the prize to guarantee this immutability is to loose all the advantages that the language offers in terms of handling Objects/Arrays. Plus, we loose the compatibility with a big amount of libraries like lodash, etc (unless we set some mappers to translate this immutable data to a plain data).

For these reasons I think we need another immutable library. In my opinion the library should:

  • Should work for Objects and Arrays
  • Guarantee immutability in the object/array. No property can be modified.
  • Should keep same interface for reading its values. This is: dot notation or brackets notation.
  • Should offer a way to guess whether we're working with a plain object/array or an immutable one.
  • Could offer same interface as native objects/arrays.
  • In case the native method applies an mutation. This behaviour should be changed [open discussion]
  • Notify when somebody is trying to mutate a property (maybe throwing an error or just logging it)

PS: I'm currently working on a library to finish this properly. Stay tunned.

edit:

This is just an approach. Obviously, those classes need a bunch of methods to work properly.

About the Object.freeze references, the problem of Object.freeze is you don't realise when somebody tries to mutate the object and, in my opinion, that's bad.

Plus, you don't get a frozen object when you extend one. So, you have to freeze the new ones every time, what is too verbose.

edit2:

Still far from the goal but here's the repo: freezr

function ImmutableArray (arr) {
arr.forEach((key, index) => {
Object.defineProperty(this, index, {
enumberable: true,
get: () => key,
set: () => {
throw new Error('cannot be mutated')
}
})
})
}
function ImmutableObject (o) {
Object.keys(o).forEach((key) => {
Object.defineProperty(this, key, {
get: function () {
return o[key]
},
set: function (v) {
throw new Error('cannot be mutated')
},
enumerable : true
})
})
}
@Alxandr
Copy link

Alxandr commented Mar 5, 2016

So, currently, you've created a semi-working version of Object.freeze()?

@bitwiselove
Copy link

@zhouzi
Copy link

zhouzi commented Mar 5, 2016

Have a look at Object.freeze, I feel like it does what you are looking for.

I agree that it's too bad that Immutable.js has an API that's so different from "vanilla" JavaScript but I think there are good reasons. The first thing to note is that it's not so much about blocking modification but mutability. You can still change an object's property value or push an item in an array but to do so it's making a new copy with the new values, preserving the original object. On the other hand, I also think that Immutable.js has a custom API for performance reasons and to avoid deeply cloning objects.

To stay the closest possible to native JavaScript, you might have to re-implement some features that mutate objects, e.g Array.push.

var push = Array.prototype.push
Array.prototype.push = function () {
  var copy = this.slice()
  push.apply(copy, arguments)
  return copy
}

But now push is returning an array instead of the array's length and might be breaking a lot of code ^^

@jcready
Copy link

jcready commented Mar 5, 2016

The benefit of using something like Immutable.js is that it optimizes the process of creating a mutated copy of the immutable object.

@coopy
Copy link

coopy commented Mar 5, 2016

Also look at seamless-immutable, which offers the native object and array API that you want (dot- and bracket-notation). In development mode, errors are thrown when attempts are made to mutate objects. In production mode, native overrides and freezes are removed, so there is no performance penalty.

@capaj
Copy link

capaj commented Mar 6, 2016

or you know, don't try to make an application state something it isn't, accept the hard truth and go with https://github.com/mobxjs/mobx :D

@carlesba
Copy link
Author

carlesba commented Mar 6, 2016

@coopy that sounds exactly what I was looking for. Thanks a lot!

@coopy
Copy link

coopy commented Mar 10, 2016

Glad I could help!

@carlesba
Copy link
Author

It's live. Check it out: https://github.com/carlesba/freezr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment