5 ms·
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
by jypie 12y ago
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 JS?
- baddox 12y agoOne 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).
- taeric 12y agoThis 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.
- baddox 12y agoYeah, 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).
- moribound 12y agoI don't follow. What's wrong with effectively undoing an edit before a redraw? Why do I care about the intermediate state?
- drifkin 12y agoI think taeric is saying you "effectively undo" an edit, meaning that you could modify the state to a new state that happens to be the same as the old state (so it'll be a different object).
- taeric 12y agoThat was exactly what I was saying. And apologies for my tone. I did not intend this to be a reason to toss immutable collections. I just don't think "easy dirty checking" is a large bonus for them.
- leebyron 12y agoOf course there's no way to know in O(1) time if you've done two edits that just so happen to sum to no-op, regardless of if you're using Immutable.js or not. However, depending on how to implement undo, you might be in good shape with Immutable.js. For example: you might keep a stack of the last few changed data around, and an undo could just pop off the stack in which case you can know if your oldData === newData in O(1). --- Keeping dirty bits around to determine when you need to operate on your data again is totally viable, there's nothing wrong with that approach, especially for smaller applications. Some frameworks designed for large applications even employ this technique. For larger applications, in my experience, the dirty bits tend to add up and create a lot of state management overhead, and soon you find a majority of your code cautiously stepping around mutable state instead of just making your application do what it's supposed to do. The primary thesis of Immutable.js (and persistent data structures in general) is to illuminate the option of having data which promises to never change and thus making memoization trivial. If you have an application which can take advantage of memoization for real performance improvements, then using these kinds of structures can be a big win.
- taeric 12y agoIf you are doing a stack, that trick works fairly easily with a mutable stack, as well. Regardless, I was not trying to toss out immutable structures with the bathwater. They are both incredibly cool and useful. Usually fairly memory intensive, though that is less of a deal today than it was in days past. Also, fairly cache unfriendly. For many applications, this is not a main concern. (32 way branching vectors, I'm looking at you.) And yes, if you have a plethora of dirty bits, that could be difficult. If you have a plethora of immutable collections, that will lead to the same trouble. Consider, the optimization at stake here is essentially adding a single "isDirty" method to existing collections that is only set true on modifications and has a "clear" method. (There are other ways this can be done, just going for the easy way.) Far from difficult to encapsulate and get the O(1) dirty checking for cheap. And I agree that applications with many dirty bits to check are difficult. You don't exactly dodge this with immutable collections. That is, in my experience, larger applications that have a lot of immutable collections tend to create a lot of management over old/new collections. Not shockingly, the trouble seems to be when you expand the scope of what you are doing wider and wider. Not necessarily how you are keeping track of modified collections.
- hajile 12y agoThe 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.
- jypie 12y agoOh, I failed to remember there was Object.freeze(). This is something the interpreter(Just-in-time compiler, to be more exact) would utilize as hints. but does this mean Immutable.js does Object.freeze()? and if so, why do we need a new library that does the same thing?
- leebyron 12y agoI think there are two concepts being confused here - this is not the same as `var` vs. `const`/`let`. Immutable.js implements persistent data structures, which are entirely runtime concepts. --- Deep copying isn't very common because it's usually a pretty obvious flag that performance might suffer, however it's the only other way to implement this same concept and that pattern is definitely found in applications which desire persistent data. You might here this referred to as "defensive copying".
- hibbelig 12y agoSay you have this code: var x = {a: 1, b: 2}; y = foo(x); // What is the value of x.b here? With mutable data structures, `x.b` might have changed. If you make `x` an immutable data structure, then you can be sure that `x.b` has not changed. This is a trivial example, but for larger programs it's going to be quite valuable to know that these kinds of changes have not happened. Maybe `foo` needs to "modify" the data structure in order to compute the final result. With mutable data structures, what `foo` will do is to create a copy of the data structure `x`: function foo(x) { x = deep_copy(x); // The following assignment changes the copy, // no effect on the original parameter. x.b = 5; } I just made up that "deep_copy" name -- I think you get what I mean. I don't know how it is written in JS. I think you can see that "deep_copy" is going to be an expensive operation if `x` is a large data structure.
- jypie 12y agoI'm afraid I don't get your point. So deep copy is expensive, and if the variable is immutable and has to be changed, it would have to be deep copied. so immutable is bad? Or are you trying to say even if it's expensive, the original variable not being corrupted is more important? I know there would be some variables that shouldn't be changed in some programs. but for this need I don't think immutable variables are necessary. Shouldn't we focus more on the aspect of performance? Thanks for the input! Please enlighten me.
- yazaddaruvala 12y agoSo, there are two cases. Situation 1: When you want to modify the original structure and use it with only its new value. Situation 2: When you want to share the original with a variation, but continue to use both the new and old structures simultaneously without them effecting each other. So from your comment, you seem to be more familiar with situation 1 and you don't seem to be considering situation 2. However, situation 2 does arise quite often in the building of highly concurrent applications. If you don't understand the benefits/need of situation 2, I can elaborate on that but right now I'm just going to explain the pros/cons of Immutability in both situations. Situation 1: You're correct, immutable data structures are more expensive in this context. They are sometimes preferred anyways (I for example prefer them), but that can and should be debated and I don't want to get into it. However, they are not as expensive as you are making it seem, there almost never needs to be a full deep copy with immutable data structures (keep reading). Situation 2: let x = { y: y, z: 1 }; let x' = copy(x); x'.z = 0; Now when x.y.a changes you don't want x'.y.a to change. To make this guarantee (that x and x' can change state independently of each other) "copy" needs to be an expensive deep copy. ie x' = deep_copy(x); However, if you were guaranteed that y and its nested children were all NEVER going to change (ie Immutable). You can now optimize: x' = shallow_copy(x); Why? because you still have the same guarantee: x.y.a will never change, thus never changing x'.y.a. x and x' are then always independent even with a simple inexpensive shallow copy. Really quick to go back to Situation 1: I hope you see here aswell that the majority of the time, you don't require deep copies. Example, ImmutableMap.put(k,v) just does a shallow copy at depth=0 since you are only mutating the HashMap itself. I am not an expert and so I'm not sure, but I think good ImmutableMaps have been optimized even further. Anyways, I hope that helps.