4 ms·
Most of the people that don't believe that immutable, persistent data structures are effective tools to increase performance of reconciliation, only put one foo
by jordwalke 12y ago
Most of the people that don't believe that immutable, persistent data structures are effective tools to increase performance of reconciliation, only put one foot in (that's my personal experience). That kind of reservation often compels people to "just try immutability on a part of their tree". It doesn't work like that and you often should go all in before you begin seeing the benefits. It's a leap of faith, admittedly.
Almost every application (ever) is a list of lists of lists (and so on). Even text can be broken up into paragraphs/code-blocks etc which form the lists. If these structures form a tree, and that tree is somewhat well balanced, then small changes can be found in log(n) time by comparing reference identity without developer intervention (by either a mixin or Om-like system). log(n) ends up being extremely fast for n in the range of graphical nodes in most UI applications. For everything else, a windowing infrastructure can be used (usually baked into a very sophisticated <ListView> component - our ReactNative mobile applications use this approach (special <ListView> component that exploits immutability without developer intervention)).
- seanmcdirmid 12y agoThanks for your reply! I work in this field and have written lots of code, both mutable and immutable, declarative, OO and functional, to solve a variety UI problems. I've also written my own language-enabled editors using multiple techniques (see comment https://news.ycombinator.com/item?id=9117234 https://news.ycombinator.com/item?id=9117234 for the one I'm working on right now, but you can see https://www.youtube.com/watch?v=SAoRWmjl1i4 https://www.youtube.com/watch?v=SAoRWmjl1i4 for an Eclipse-based one I did in 2007), so I've definitely got multiple feet in the game. I don't work in Web, most of my UI code was written for Swing, SWT (Eclipse), and these days WPF in immediate mode. It seems like React is solving a bunch of JS/DOM problems, so maybe my experience doesn't transfer, but I've found that for my work, it is much easier to just go with mutable data structures that support change propagation, so you make a change that affects a line in a block (my current editor architecture, block - lines - more blocks - more lines - etc...), the change is just...O(1) because the line can be damaged/repaired directly! So why would I give that up for O(log(n))?
- jordwalke 12y agoIt's a great question. All of this (immutability) only makes sense to even attempt if you believe that immutability is easier to reason about than mutability. If we don't agree there, then I have nothing more to add really. But assuming we agree, then there is the question of performance. In most applications, we have three tiers of time durations. Tier One: During an interaction/animation you must update the screen every 16ms. Code may not run longer than 16ms (less in practice). Tier Two: You are not interacting, but may begin interacting with something at some unknown time. Code may not block the UI thread for longer than about 50ms so that there is a guarantee of not introducing perceivable delays into the interface. Tier Three: Long running tasks which should be executed in parallel with the UI thread/process. If going from O(1) to O(log(n)) still allows you to meet your deadlines for whichever latency tier you are targeting in whichever supported device classes you want to support, then it's worth it in order to program with better abstractions. Blocking for 1ms is as good as blocking for 13ms in Tier 1. Blocking for 25.5 is as good as blocking for 40ms in Tier 2. (This is helped by a decent event loop/task scheduler etc). Again, all of this assumes you genuinely value immutability as a programming paradigm over mutability. If you'd really rather mutate, then you should just be using mutations/observables. I would not rather. Sometimes, I still perform mutations for the most critical parts of a UI abstraction (such as a scroller animation etc) - but I am up front about it being a compromise of what I'd rather do.
- couchand 12y agoHoly cow this may be the most salient explanation of these various concerns I've seen. Blocking for 1ms is as good as blocking for 13ms in Tier 1. +1. Let's use all the resources we have available, and also make sure we understand where those resources are coming from. If one of our resources is user perception time we need to manage that just as we manage memory and CPU usage.
- robmcm 12y agoYour argument seems to stem from immutability is easier to reason, therefore you are willing to give up performance to accommodate it. You stated that in some cases it doesn't matter if you use 1% or 100% of processing time in the current frame which I would argue is risky. The more complex your application the more expensive handling wholesale changes becomes, unless you have something like react managing change detection you are going to suffer. From my point of view this is the interesting part of react, you hand off the task of change detection to generic, tested code. However it's still going to be slower than the alternative for fine grain changes. It's also worth noting that on larger applications where you modularise common components, you typically push complexity down the chain. Take a data grid for example, do you process the data for every cell up front, or do you do it only when the cell is rendered. If it's the latter mutability of that data structure is really important, otherwise one little change is going to cost you far too much.