The push-pull approach described here actually sidesteps the worst glitches because the dirty-flag propagation is just marking, not computing. But the article glosses over what happens during the pull phase when the dependency graph has diamonds. Topological sorting during pull is the standard fix -- Preact Signals and SolidJS both do this -- but it adds complexity that matters if you are rolling your own.
Flapjax was doing a lot of this right in 2008. It is wild that the JS ecosystem took another 15 years to converge on essentially the same core ideas with better ergonomics.
And a lot of literature on the algorithms.
I wrote a bit about the connection here:
https://blog.metaobject.com/2014/03/the-siren-call-of-kvo-an...
(It starts in a slightly different place, but gets there)
Also about constraints as an architectural connector.
https://dl.acm.org/doi/10.1145/2889443.2889456?cid=813164912...
The system as described isn’t actually glitchy, is it? It doesn’t eagerly run any user computations, just dirtying, and that is idempotent so the order is irrelevant. It’s also a bit useless because it only allows you to pull out values of your own initiative, not subscribe to them, but that’s fixable by notifying all subscribers after the dirtying is done, which can’t cause glitches (unless the subscribers violate the rules of the game by triggering more signals).
So now I’m confused whether all the fiddly priority-queue needlepoint is actually needed for anything but the ability to avoid recomputation when an intermediate node decides it doesn’t want to change its output despite a change in one of its inputs. I remember the priority queue being one of the biggest performance killers in Sodium, so that can’t be it, right?..
I’m also confused about whether push-pull as TFA understands it has much to do with Conal Elliott’s definition. I don’t think it does? I feel like I need to reread the paper again.
Also also, some mention of weak references would probably be warranted.
Virtually nothing that is getting sold/branded as "FRP" has anything to do with Conal Eliott's definition.
I once gave a long talk about this here in Berlin, but I don't remember if there was a video.
I've also explained it on twitter a bunch of times, including this memorable sequence:
https://x.com/mpweiher/status/1353716926325915648
Kinda like the Marshall McLuhan scene in Annie Hall ("if only real life were like this")
> Virtually nothing that is getting sold/branded as "FRP" has anything to do with Conal Eliott's definition.
True but not what I meant. The article implicitly (and, in the links at the end, explicitly) refers to his 2009 paper “Push-pull functional reactive programming”, which describes a semantic model together with an specific implementation strategy.
So I was wondering if TFA’s “push-pull” has anything to do with Elliott 2009’s “push-pull”. I don’t think so, because I remember the latter doing wholly push-based recomputation of discrete reactive entities (Events and Reactives) and pull-based only for continuous entities that require eventual sampling (Behaviors).
With that said, I find it difficult to squeeze an actual algorithm out of Elliott’s high-level, semantics-oriented discussion, and usually realize that I misunderstood or misremembered something whenever I reread that paper (every few years). So if the author went all the way to reference this specific work out of all the FRP literature, I’m willing to believe that they are implying some sort of link that I’m not seeing. I would just like to know where it is.
I've gone with the universal `alien-signals` package for my project (which doesn't use a frontend framework that includes signals). They show benchmarks of being by far the fastest and have strict limits on code complexity. Those limits are also supposed to avoid glitches by design, and now at least some of that is tested[1].