![]() ![]() But de-registering something doesn’t really feel natural in Clojure or even Java code, and there’s no way to enforce that every resource that is no longer needed will be properly disposed of.Ī common solution is to make downstream references weak. Meaning, new dependencies will come and go. It’s so easy to accidentally lose a reference in a garbage-collected language!Īnd this is what I am struggling with. We can introduce dispose method that could be called to unregister itself from upstream, but nobody can guarantee that users will call that in time. Meaning, the previous version of the signal will still be referenced from *object along with the new one: Well, due to the nature of signals, they actually keep references to both upstream (for re-calculation) and downstream (for invalidation) dependencies. The simplest example: we’re in REPL and we re-evaluate (def label. Irresponsible, I know, but things happen, especially in end-user code. Now imagine we lose a reference to the label. We implement a mixed push/pull model: recalculating values is lazy (not done until explicitly requested), but marking as dirty is eager (immediate dependencies are marked as :dirty and their transitive deps are marked with :check, which means might or might not be dirty): One important feature we’re missing in our incremental framework is effects. And we’ll have to provide enough incremental versions of base core functions to keep everyone happy, and potentially teach them to write their own. One can imagine that we’ll need incremental versions of filter, concat, reduce etc, and our users will have to learn about them and use them if they want to keep stable identities. The bad news is, you have to think about it, whereas in React model you usually don’t bother with such minute details at all. Either way, at least you can choose where it happens. I can imagine it could be better when a diff happens on the data layer instead of on the final UI layer because generated UI is usually much larger than the source data. Imagine we have a list of todos and a function to render them. To be called incremental we must somehow reuse, not just re-run, previous computations.Ī simple example. What we have so far is, I believe, called reactive, but not incremental. Now let’s dig into implementation details a little bit. On the other hand, how often do you change fonts in the entire app? Should it really be optimized? The question of whether this use case is important remains open. Well, incremental computation solves this problem beautifully! If you make your default font a signal, then only components that actually read it will subscribe to its changes: it shouldn’t affect paddings, backgrounds, or scrolls, but should affect labels and paragraphs. In a perfect world, though, font-ui change should only affect components that actually use that font. When the time for the update comes, the whole UI will be re-created: If you pass font-ui as an argument to every component, it will create a false dependency for every intermediate container that it passes through. The actual details don’t matter, but the point is: there’s a default theme at the very top of your app and a label somewhere deep down. One of the examples where VDOM model doesn’t shine is props drilling. But stable objects in a dynamic enough UI? Lack of diffing and VDOM? This is something I can use. I don’t really care about optimal performance, because-how much is there to compute in UI anyways?Īnd also-it’s not obvious to me that if you make every + and concat incremental it’ll be a net win because of overhead. This was my main motivation to look into incremental computations. We can put all internal state into objects as fields and not invent any special “more persistent” storage solution at all! No state tracking and positional memoization either. Same DOM node, if we were in the browser.Ĭool? Cool! No diffing needed. for rendering or layout, it will always return exactly the same instance of the checkbox and text field. And the beauty of it is unless the user switches a tab or plays with a checkbox, *tab-content will be cached and NOT recomputed because its dependencies do not change!Īnd that means that no matter how many times we dereference *tab-content e.g. ![]()
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |