-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide "what changed" array (of Booleans) to derived stores #6777
Comments
Like #6750, this would probably be a breaking change for anyone creating custom derived stores, because the Typescript definition of the callback passed to |
The answer is probably performance/gc (is it though?), but why not pass an array like |
I thought of this while working on implementing #6750, when I saw that the code tracks a The only downside to a boolean array, then, is a performance cost that I think would be slight, but would be worth measuring. Every derived store would create an extra array of N booleans, where N is the number of stores the derived store is subscribing to. Would that extra array per store, and the work done to keep it up-to-date, be worth the performance cost? The performance cost of one extra int per store would be minimal, but I don't know the performance cost of an extra array. I suspect the better DX will make it worth it, though; I'll think about it.
I actually had a third store in my original example and then realized that the example was getting bigger than it needed to be. Missed the fact that it would hide the bitmap-ness of the check needed. |
Please take anything I say with a grain of salt, I've never needed a derived store and it's my first time looking at the store source.
I figured that and on first sight it does seem like a viable idea. I don't know why the original code went with a bitmap, I assume nobody tried to use a derived store with more than 32 stores yet? Or maybe people do and don't know they run into undefined behavior? Or am I missing something and it doesn't break with 33 stores? And it's entirely plausible that there are situations (like in a game or simulation) where you automatically create derived stores of dynamic length > 32.
Does it act funny? I thought the store would use this array write-only? Reset it using
I'd be surprised if the difference can be measured, but I'm curious if you really want to set up a benchmark. But looking at the current implementation there is also a
Only track it if svelte/src/runtime/store/index.ts Line 164 in e45d180
|
The bit that would break with more than 32 stores is the Lines 234 to 254 in e45d180
See how the So if derived store C were deriving from 33 or more stores, including store A in the 33rd or later position, and it also happens to be deriving from store B in the 33rd or later position, and store B derives from store A, then there would be a glitch where store A updating would cause store C to see store A's new value with store B's old value once, then a second update with store A's new value with store B's new value. Was that paragraph as clear as mud? :-) Then you'll see why nobody has run into this issue yet, because it's something that could almost never happen. Though perhaps it would be best to document this situation and say "There's a practical limit of 32 stores" or something. |
@rmunn thanks for the explanation! I also dug into the store code a bit. I was a little confused about the second argument to Also TIL the iteration order of |
Just realized that with a Boolean array, you can use array dereferencing just as you can with store values. So instead of writing |
FYI, here is a diagram of a diamond dependency:
graph TD
a --> b --> d
a --> c --> d
Tracking "pending" and the undocumented second argument to subscribe is for ensuring Worth noting that it doesn't handle what I call the "diamond+ dependency" problem: graph TD
a --> d
a --> b --> d
a --> c --> d
in this case, when Pulled from the documentation of one of my store libraries. See: @crikey/stores-base/README.md for more dependency examples |
I can see utility with this proposal. I would suggest some discussion around the callback signature though: With the proposed signature Furthermore, I do wonder if this belongs in the basic implementation of 1 a user could access the provided argument via the arguments array. but.. yuck |
I agree that discussion about the callback signature is useful. However, there's nothing wrong with not using a parameter, and calling it var d = derived([parent1, parent2], (values, _s, _u, changed) => "some derived value"); This signals that you're not using the |
Since runes now are the primary way to do reactivity, and they work outside components, too, stores have less of an impact now, and as such we're not going to implement store features that are rather niche. Therefore closing. |
Describe the problem
When a derived store has multiple parent stores, its callback might sometimes want to know which parent store changed and triggered the callback. This would mostly be useful in advanced callbacks that use
set
(and, if #6750 is merged,update
) to calculate their value.Describe the proposed solution
The derived store's callback could take an optional parameter after
set
(and afterupdate
, if #6750 is merged), which would be an array of Booleans describing which parent store(s) were updated. The Booleans would be in the same order as the parent stores, i.e. ifstores[i]
was updated, thenupdated[i]
(orchanged[i]
, see naming discussion below) would be true.This would actually be quite simple to implement, looking something like this:
Of course, type definitions would also need to change, so the actual PR would have more to it than that. But the core of this feature can be implemented in just four lines of code.
Alternatives considered
Some use cases for this feature can be handled with the status quo:
Perhaps not the best example, as the manualDiscounts store is simpler to read than the version with a
changed
array. But imagine a complex state being stored in the derived store: the current user, the shopping cart contents, and data about the product being viewed right now (product description, review scores, top five reviews...).Importance
nice to have
Miscellaneous information
The first version of this proposal asked for a bitmap instead of a Boolean array. But once I realized that array destructuring would allow giving names to the items in the array, so that you could write
[priceChanged, discountChanged]
and then referencepriceChanged
instead ofchanged[0]
, the Boolean array version of the idea became much, much better, so I abandoned the bitmap idea.The text was updated successfully, but these errors were encountered: