letsfreezethat
Advanced tools
Comparing version 3.0.1 to 3.0.2
@@ -32,6 +32,7 @@ (function() { | ||
while (k--) { | ||
if (!(((v = d[k]) != null) && ((typeof v) === 'object'))) { | ||
continue; | ||
if (((v = d[k]) != null) && ((typeof v) === 'object')) { | ||
R[k] = deep_copy(v); | ||
} else { | ||
R[k] = v; | ||
} | ||
R[k] = deep_copy(v); | ||
} | ||
@@ -43,6 +44,7 @@ return R; | ||
v = d[k]; | ||
if (!((v != null) && ((typeof v) === 'object'))) { | ||
continue; | ||
if ((v != null) && ((typeof v) === 'object')) { | ||
R[k] = deep_copy(v); | ||
} else { | ||
R[k] = v; | ||
} | ||
R[k] = deep_copy(v); | ||
} | ||
@@ -67,6 +69,7 @@ return R; | ||
while (k--) { | ||
if (!(((v = d[k]) != null) && ((typeof v) === 'object'))) { | ||
continue; | ||
if (((v = d[k]) != null) && ((typeof v) === 'object')) { | ||
d[k] = deep_freeze(v); | ||
} else { | ||
d[k] = v; | ||
} | ||
d[k] = deep_freeze(v); | ||
} | ||
@@ -77,6 +80,7 @@ return shallow_freeze(d); | ||
v = d[k]; | ||
if (!((v != null) && ((typeof v) === 'object'))) { | ||
continue; | ||
if ((v != null) && ((typeof v) === 'object')) { | ||
d[k] = deep_freeze(v); | ||
} else { | ||
d[k] = v; | ||
} | ||
d[k] = deep_freeze(v); | ||
} | ||
@@ -129,3 +133,3 @@ return shallow_freeze(d); | ||
//----------------------------------------------------------------------------------------------------------- | ||
nofreeze_lets = function(original, modifier = null) { | ||
lets.nofreeze = nofreeze_lets = function(original, modifier = null) { | ||
var draft; | ||
@@ -132,0 +136,0 @@ draft = nofreeze_lets.thaw(original); |
{ | ||
"name": "letsfreezethat", | ||
"version": "3.0.1", | ||
"version": "3.0.2", | ||
"description": "An utterly minimal immutability library in the spirit of immer", | ||
@@ -5,0 +5,0 @@ "main": "./freeze.js", |
@@ -23,5 +23,3 @@ | ||
- [Benchmarks](#benchmarks) | ||
- [Other Libraries, or: Should I COW?](#other-libraries-or-should-i-cow) | ||
- [`klona`, `deepfreeze`, `deepfreezer`, `fast-copy`](#klona-deepfreeze-deepfreezer-fast-copy) | ||
- [Should I COW?](#should-i-cow) | ||
- [Other Libraries](#other-libraries) | ||
- [To Do](#to-do) | ||
@@ -122,2 +120,4 @@ | ||
The `nofreeze` flavor is around 3 to 4 times faster on `freeze()`. | ||
The `lets()` method has a number of attributes which are callable by themselves (no JS tear-off / | ||
@@ -129,28 +129,21 @@ `this`-juggling here): | ||
* **`freeze = ( d ) ->`**—deep-freeze in-place; a no-op with `nofreeze`. | ||
* **`thaw = ( d ) ->`**—thaw a deep copy (in the `freeze` flavor) of `d` and return it; | ||
* **`get = ( d, key ) ->`**—return value of an attribute of `d`. | ||
* **`set = ( d, key, value ) ->`**—set an attribute of a copy of d, return the copy. | ||
* **`thaw = ( d ) ->`**—return a deep copy of `d` (thereby un-freezing it). | ||
* **`get = ( d, key ) ->`**—return value of an attribute of `d`. Equivalent to `d[ key ]` and just there | ||
to complement `set()`. | ||
* **`set = ( d, key, value ) ->`**—make a deep copy of `d`, set attribute `key` to `value`, and return | ||
the (frozen or unfrozen depending on flavor) copy. Prefer to use `assign()`, `thaw()`/`freeze()`, or | ||
`lets()` whenever you want to modify more than a single attribute as `set()` will deep-copy and | ||
deep-freeze# on each call. | ||
## Notes | ||
* LFT does not copy objects on explicit or implicit `freeze()`. That should be fine for most use cases since | ||
what one usually wants to do is either create or thaw a given value (which implies making a copy), | ||
manipulate (i.e. mutate) it, and then freeze it prior to passing it on. As long as manipulations are local | ||
to a not-too-long single function, chances of screwing up are limited, so we can safely forgo the added | ||
* LetsFreezeThat does not copy objects on explicit or implicit `freeze()`. That should be fine for most use | ||
cases since what one usually wants to do is either create or thaw a given value (which implies making a | ||
copy), manipulate (i.e. mutate) it, and then freeze it prior to passing it on. As long as manipulations | ||
are local to a single function, chances of screwing up are limited, so we can safely forgo the added | ||
overhead of making an additional copy when either `freeze()` is called or a call to `lets d, ( d ) -> ...` | ||
has finished. | ||
has finished. Observe that when being given a value `d` it is not necessarily safe to `freeze()` it since | ||
another party may still hold a reference to `d` and assume mutability. When in doubt, use `freeze thaw d` | ||
to freeze a deep copy of `d`. | ||
* The idea is that you can switch to the more performant `nofreeze` flavor in production: | ||
```coffee | ||
if running_in_dev_mode then { lets, freeze, thaw } = require 'letsfreezethat' | ||
else { lets, freeze, thaw } = ( require 'letsfreezethat' ).nofreeze | ||
``` | ||
once you have made it sufficiently plausible that no part of your code performs unintended mutation of | ||
values chalked up as immutable. Yes, it's all about probabilities rather than proof of correctness. | ||
* The non-freezing configuration is a tad faster on `thaw()` and ≈5 times faster on `freeze()`. | ||
* Observe that the `thaw()` method will always make a copy even with the `nofreeze` flavor; | ||
@@ -164,2 +157,3 @@ otherwise it is hardly conceivable how an application could switch from the slower `{ freeze: true, }` | ||
## Implementation | ||
@@ -286,15 +280,12 @@ | ||
## Other Libraries, or: Should I COW? | ||
## Other Libraries | ||
During the implementation of LetsFreezeThat I realized there's quite a few packages available that do | ||
immutability in JavaScript, e.g. | ||
Libraries that do deep freezing and/or deep copying and/or provide copy-on-write semantics that are | ||
available on [npm](http://npmjs.org) include [`immer`](https://immerjs.github.io/immer/docs/introduction), | ||
[`HAMT`](https://github.com/mattbierner/hamt), [`mori`](https://swannodette.github.io/mori/), | ||
[`immutable.js`](https://immutable-js.github.io/immutable-js/), | ||
[`fast-copy`](https://github.com/planttheidea/fast-copy), | ||
[`deepfreeze`](https://github.com/serapath/deepfreeze), and [`deepfreezer` (a.k.a. | ||
DeepFreezerJS)](https://github.com/TOGoS/DeepFreezerJS). | ||
* [`HAMT`](https://github.com/mattbierner/hamt) | ||
* [`mori`](https://swannodette.github.io/mori/) | ||
* [`immutable.js`](https://immutable-js.github.io/immutable-js/) | ||
and, last but not least, | ||
* [`immer`](https://immerjs.github.io/immer/docs/introduction). | ||
**`immer` provided the inspiration**—The key idea of `immer` is that in order to achieve immutability in | ||
@@ -316,5 +307,2 @@ JavaScript, instead of inventing one's own data structures and APIs, it is much simpler to just recursively | ||
### `klona`, `deepfreeze`, `deepfreezer`, `fast-copy` | ||
**most deep-copy algos too slow**—In search for a fast solution that would only provide deep-copying (i.e. | ||
@@ -326,3 +314,3 @@ no copy-on-write / structural sharing) and/or deep-freezing capabilities I found | ||
that only `klona` was likely to bring speedups to the next version of LetsFreezeThat so I did not consider | ||
the rest any more. Deep-freezing nested compound values in-situ is almost exactly the same as deep-copying | ||
the rest any more. Deep-freezing nested compound values in-place is almost exactly the same as deep-copying | ||
nested compound values so I used `klona`'s approach for both chores. Be it said though that I did not | ||
@@ -333,12 +321,10 @@ evaluate other possibly interesting aspects of any of these packages, so if your use cases involves copying | ||
### Should I COW? | ||
**Should I COW?**—Copy-On-Write is a technique to eschew 'speculative', avoidable memory consumption. Phil | ||
Bagwell suggested how to efficiently leverage structural sharing for trees of data in [a paper titled *Ideal | ||
Hash Trees* (Lausanne, 2000)](http://infoscience.epfl.ch/record/64398/files/idealhashtrees.pdf); | ||
subsequentially, his approach was implemented by the [Clojure](https://clojure.org/) community to get more | ||
memory-efficient and performant COW semantics into the language. Alas, according to my benchmarks HAMT is | ||
still not fast enough in JS to justify the effort when your data items are small as you'll only get 5%—25% | ||
of the performance that you'd get with naive copying. | ||
**HAMT a solution for COW, *but***—Copy-On-Write is a (not new) technique to eschew 'speculative', avoidable | ||
memory consumption. One Phil Bagwell proposed a technique how to do that efficiently for trees of data in [a | ||
paper titled *Ideal Hash Trees* (Lausanne, | ||
2000)](http://infoscience.epfl.ch/record/64398/files/idealhashtrees.pdf); subsequentially, his technique was | ||
used by the [Clojure](https://clojure.org/) community to get more memory-efficient and performant COW | ||
semantics into the language. **Q**: What's not to like?—**A**: It's *still* not as fast in JS to justify the | ||
effort when your data items are small; again, see the [benchmarks](#benchmarks). | ||
## To Do | ||
@@ -351,2 +337,2 @@ | ||
case of immutable maps | ||
* [ ] consider to optionally detect multiple object instances, circular references |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
39968
146
330