00:17
<littledan>
Watcher is about notifying "something may be going on with something in this set of things that I care about", and then letting you (later) access that going-on subset. I haven't heard of a pub-sub thing with a requirement like that. Using the signals directly to represent themselves, as opposed to a subscription object, saves lots of allocations in a hot path. And there's no payload--also unusual for pub/sub systems (since you get the payload by reading the computed, and computeds are not pub/sub)
00:22
<littledan>
ljharb was quibbling with this point, and he's not wrong about the fetch precedent. That said, I really liked your point (the "simple effects" people intuit they want are a DOM feature).

Yes, I am sympathetic with this inevitability of direct use... I would like to improve the ergonomics as much as possible, as long as the proposal still works (e.g., not introducing too much runtime overhead).

The main thing that's relevant here is, you shouldn't use Watcher objects as if they represent a subscription to a Computed. You can sort of do this, but we want to discourage that usage style--Computeds are supposed to exist within a lazily evaluated dependency graph.

Overusing Watchers moves you back towards push-based reactivity. It causes more "loops" until all the values "settle". It's like overusing useEffect in React.

10:06
<Duncan MacGregor>
I would strongly support rbuckton's suggestion of adding a better idea of references, and then building signals on top of that as a type of reference. References feel like they carry their own weight as a feature much better than Signals do on their own.
12:58
<littledan>
There was a lot of skepticism to the idea of references when they were introduced to committee previously. What should be the next steps there? (I was hallucinating) I'm pretty worried that the committee would be really negative about that idea.
12:58
<littledan>
(I think they'd be cool, personally)
12:59
<rbuckton>
Was something similar ever presented? I haven't proposed it yet
12:59
<rbuckton>
I've briefly mentioned them on occasion, but nothing formal as of yet
13:04
<littledan>
oh sorry I got confused... probably I'm thinking of when I floated the idea of variable decorators... sorry for the confusion on my part!
13:04
<littledan>
actually I'm not sure if I actually brought that to committee either
13:05
<littledan>
but, I really don't want to block signals (which are perfectly expressible within JS as it is today) on something fundamental about how variables work (which might be nice but also IMO would compose well "on top")
13:07
<littledan>
In an earlier design, we had the notion that you could pass a computed a callback function that would trigger when it was made dirty. The downside was that you had to pass this upon construction of the computed, which meant interoperability was impaired. However, it could be modelled differently. Is that better than having a watcher?
and this was a special computed which we called an "effect" -- normal computeds would definitely not work this way; it's just not the programming model for computeds.
13:08
<littledan>
I don't think there's anything in signals which is pub/sub.
13:20
<littledan>
At least I think of "sub" as subscribing to the data which is published--signals, even the watcher, doesn't have an API like this.
13:22
<littledan>
I wanted to go with Signal/State/Computed because they approximated ecosystem consensus for terms, so I though they'd be the most straightforward reference point
13:23
<littledan>
The signals proposal does something in between. There's always a counter that can be used for invalidation, and you can form a strong connection from state->effect (via a watcher). The invalidation itself works the same in both cases though (e.g. the cache is invalidated not via a watcher but via the counter)
the counter is kinda an implementation detail, and implementations can drop it while a signal is connected, if they want to
13:23
<littledan>
my mental model matches trueadm's
13:26
<littledan>
definitely not more things with Abort in them, at least
13:27
<littledan>
somehow the terrible naming there (plus the high level of difficulty of using AbortSignal/AbortController correctly without leaks) makes me feel like, uniquely, we actually could make another cancellation API
13:27
<littledan>
Yeah the question is whether the state is "well-behaved"
14:41
<ljharb>
fwiw i think references would be a very dangerous concept to add to the language
15:10
<rbuckton>
fwiw i think references would be a very dangerous concept to add to the language
Why?
15:11
<ljharb>
they’re hard to understand and can be an easy footgun. people already misunderstand object mutation behavior in terms of references.
15:11
<ljharb>
if you want a live version of a value, we already have functions and getters (and I’ve often heard live export bindings described as a mistake)
15:19
<rbuckton>
Specifying arrows to handle both read and write, or an object with getters and setters, is a lot of boilerplate that could be reduced down to a single character. Decorators could sorely use them and are the reason I drafted a proposal for refs ages ago. The repetition of () => for every relationship in an ORM and for DI binding gets quite exhausting after awhile.
15:24
<rbuckton>
And long term I think there will be sufficient motivation for private fields in shared structs, such as to ensure you use methods on the struct to ensure reads and writes to the field are atomic. To support that scenario, though, you need to be able to pass some kind of reference to Atomics.load/Atomics.store/Atomics.compareExchange/etc., and there's no other way to do that presently.
15:29
<rbuckton>
They would be a powerful feature, but I do believe they need a large number of motivating use cases before they should be considered. That's why I haven't brought the proposal to plenary yet. Decorators alone weren't sufficient motivation, IMO, and even then it took a long time for Decorators to reach Stage 3. Decorators + Private Names in Shared Structs + Signals + multiple return value efficiencies over array destructuring might be close enough, but there's still a ways to go for some of those.
16:06
<littledan>
my other idea to avoid () => was to make prefix ^ before an expression to be our "lightweight arrow function" syntax
16:07
<littledan>
(doesn't address atomics references, or references to a map entry, etc)
16:07
<rbuckton>
That doesn't help with setters though.
16:07
<littledan>
nope it doesn't
16:08
<rbuckton>
Its also still a function with call overhead. With & an implementation could theoretically inline the reference if both the argument and the parameter are refs.
16:10
<Yehuda Katz>
littledan: And I think ecosystem consensus matters more than my aesthetics, which is why I didn't even advocate for a change once, even privately :)
16:12
<littledan>
do you think this would be realistic to do in a baseline bytecode interpreter? function calls are already inlined during higher JIT modes
16:13
<littledan>
in some sense, a traffic signal is just there, and you look at it when it's relevant to you :)
16:14
<Yehuda Katz>
I will inform my driving instructor 😆
16:14
<littledan>
oh yeah I don't drive...
16:14
<Yehuda Katz>
me neither
16:14
<Yehuda Katz>
that's why I'm 41 and have a driving instructor
16:15
<rbuckton>
Sorry, inlining is the wrong term here. I described & as being a syntactic transform. What I'm saying is that if you use & for both the argument and the parameter no such transform needs to occur and the Reference, not the value, is passed as the argument.
16:17
<rbuckton>
By passing the reference, reads and writes would just occur against the referenced binding without any function call overhead or additional stack space.
16:18
<rbuckton>
Since this could be analyzed statically, its possible this could be handled at any layer.
16:21
<rbuckton>
You might not be able to optimize away a reified ref, but then you're still no slower than a function call might be.
19:09
<trueadm>
I'm really interested in the Reference proposal idea. If you have any draft notes somewhere, I'd love to read them. I think they'd really help solve a big problem with Svelte 5's new reactivity model in how we can "pass" reactivity around boundaries such as functions and modules. We've been pushing the community towards using closures and getters/setters, but there's been a lot of resistance as they just find it cumbersome. We've been holding off adding more Svelte compiler magic because it skews the lines of what's really happening.
19:19
<littledan>
Since this could be analyzed statically, its possible this could be handled at any layer.
yeah this kind of thing sounds like a bytecode interpreter might be able to handle it...