3 ms·
It'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. I
by jordwalke 12y ago
It'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.
- seanmcdirmid 12y ago> 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. Ok, that makes a lot of sense. I spend a lot of time trying to make mutability easy to reason about (my research), so I agree on the problems but disagree on solution strategies (fixing mutability with managed time vs. avoiding it). There are plenty of differing and evolving opinions in this field (e.g. back in the early 90s, constraints were going to save us). I see as the main benefit of React is that there is no need for change propagation, just do a fast diff at the end. That's interesting and could be an overall win given the constant overhead of change propagation (O(1) with lots of bookkeeping), but I'm not sure how that would scale in practice. One of the reasons I moved on from declarative UIs (I did my dissertation on one called SuperGlue) was because the paradigm is difficult to scale in expressiveness (let alone performance) beyond simple examples; e.g. I couldn't build interactive compilers bolted onto seamlessly onto editors for richer programming experiences.
- jordwalke 12y agoAh, it's good to know we have an ally against a common foe and I respect that you're taking a different approach (I suspect you'd be interested in Mezzo). I'd really encourage you to try out React though. It's different than other FRP type systems because the granularity of "reactivity" is much larger (at the component level) which means the majority of your code executes on plain data structures such as arrays and objects. There's no need to continuously be lifting your data into some "reactive" data container. For example, if you have two numbers that are changing over time, if you want to add them, you use the + operator instead of creating some kind of "ReactivePlus" operator. Also, in some types of apps, when you have many of these point to point bindings wired up, the bookkeeping of them can start to add up too, especially when everything ends up changing any time anything small changes. This hurts two cases predominantly: 1. Your initial rendering of the UI. You usually have to set up these point to point bindings. It would be faster to not have to when blocking the initial user experience (which is critical). 2. When small changes end up rerendering the entire page anyways. This is the worst time to be slow because you already have so much to do! If some small imperceivable delay becomes a medium imperceivable delay, it's not so bad. But when the entire scene changes all the time, a framework like React that anticipates this can cut right to the chase and do the rerendering without also having to do the bookkeeping along the way. Different apps will have different sweet spots in different paradigms. I will say that it's worked out well for us at Facebook/Instagram and many other serious production apps (not just simple examples). I'd encourage you to try it out and give us more feedback since you've done so much research in this area.
- burntcaramel 12y agoAlso as an application gets more complex, it may be harder to keep the juggling act of mutable structures going, and keeping them as fast as they were before. Mutable structures have a tax that you often must pay with complexity. Immutable structures and React’s declarative approach have more of a flat tax, with means complexity and performance are much more predictable.
- mattmcknight 12y agoIf the DOM itself is mutable, a primary philosophical problem I have with layering an immutable abstraction on top of it is that the inevitable leaks from things that lie outside of the immutable abstraction are hard to deal with. It certainly makes sense to me to use immutable approaches in pure abstractions, but the world is mutable, so you have to be extremely clever to abstract that away.