Fork me on GitHub
#matrix
<
2023-12-28
>
alandipert19:12:34

i was reflecting on the history of javelin recently and concluded something i'd be curious to receive validation on from an outside expert

alandipert19:12:33

i know that broadly reactivity can be done either "push" or "pull". push (javelin) is when you propagate values when they're set; "pull" (reagent, matrix?) is when setting a value merely invalidates a cache, and it's looking-at/dereferencing the graph that causes the cascade of requisite computation

alandipert19:12:05

each have their tradeoffs, but there's one that i didn't realize was a tradeoff until reflecting. in the pull system, since writing/modifying is merely cache invalidation, "in-transaction" (function calls on same stack) values are consistent with respect to one another. that is, you can modify a reactive value and refer to it on the same stack and not be surprised by its value, since writing does not necessarily trigger reactive effects

alandipert19:12:51

i realized that in javelin we had to simulate this with our dosync construct, which is a delimited pull system of sorts. but in a full pull system you get it for free. does that overall seem not insane and/or correct?

kennytilton20:12:03

Perhaps a quibble, but Matrix does have lazy cells, of different varieties: lazy until read once, always lazy, lazy after intially evaluating eagerly. And another quibble: observer aka watch side-effects are dispatched immediately when each property changes, tho a "deferral" mechanism exists (a) so watches can enqueue a different MX state change or (b) so actions can be deferred to an optional client handler that runs after every change to de-dup/reorder/whatever actions recorded for it by watches. Possible quibble, Reagent does IIRC eagerly dispatch view functions when ratoms change. But I get that that is "pull" for everything else. This one I do not grok, and seems important:

you can modify a reactive value and refer to it on the same stack and not be surprised by its value, since writing does not necessarily trigger reactive effects
Does "not be surprised" mean I expect the value to appear modified or not? The follow-up "since writing does not trigger..." makes its sound like I would not see the new value. Anyway, lazy or not, user code in Matrix cannot read an obsolete value, because currency is guaranteed by the read API. I call it JIT consistency. Note that this then applies to watch functions, which may read other properties to execute their side effects: they are guaranteed to see any effect of the original modification. Fun note: cell X aborts its change processing if it discovers it is already completely changed. How? Because a watch function on some cell Y, dependent on X, fired and asked for X. The second (or third or fourth) time through recursively, X was allowed to finish in peace, and when higher stack change processing sees that, it just stops. Scroll down https://tilton.medium.com/the-cells-manifesto-b21ed10329f0 to "Data Integrity" for more a few more deets. As for Javelin's dosync, MX used to have a macro "with-one-pulse" that did not propagate until the body was executed. I looked at resurrecting that a couple of months ago when I saw an event handler kicking off two cell changes, and it seemed they should be one change, if only for efficiency. But I decided to wait for a good use case. I think I have muddied the waters sufficiently 🤯 so I will await follow-ups. tl;dr Our mental models do seem to differ.

alandipert20:12:28

thanks this is all great, will digest and bbl simple_smile

👍 1