1. 21
    1. 13

      I feel the language should move slow. Signals were in vogue recently with the JS frameworks. Each one implementing their own version. That doesn’t mean the language needs to adopt it.

      I think JS could do with less language features, as opposed to more. The more language features it has, the less productive I have become when using it.

      1. 8

        This would be a standard library function, not a language feature. And the authors demonstrate examples of signals in popular JavaScript frameworks going back over a decade. It’s not a fad.

        1. 1

          The earliest example I can think of—and perhaps it dates back further—is SproutCore’s SC.Observable, which was part of its initial release in 2010. The concept has evolved somewhat over the last 14 years, but I agree: this is a fairly baked JavaScript pattern as far they go.

          1. 1

            This would be a standard library function

            JavaScript doesn’t have a standard library to my knowledge.

            1. 6

              Javascript has global values that act as a pre-imported standard library, kind of like how Rust automatically imports std::prelude.

              This would be a new global namespace (Signal) acting essentially like a new library.

                1. 2

                  You’re right, I meant to write Signal and apparently didn’t notice the typo, sorry!

                  1. 1

                    I think Symbol was an example as to how this would work…but it wouldn’t even be that much friction to create a polyfill since Signal seems to be “new-able” (whereas Symbol throws a TypeError if you try and instantiate it).

          2. 4

            After working few years with reactive programming when Swift was released, and with Elm before it dropped reactivity/signals style in 2016, I believe it is not the ideal abstraction for UI, at least for me. In this proposal, it complexifies javascript even more, without a clear benefit. I remember 10 years ago RP/FRP was very hyped and I liked it a lot, but in my opinion it aged poorly - But I would like to head contrary experiences.

            1. 2

              Language proposals are fine and all but is there anybody in these that keeps an overview and looks at the whole picture?

              1. 1

                I’m very curious about how the “automatic dependency tracking” would work.

                1. 3

                  Seems like it’s based on tracking with Signals are accessed when a given Signal is evaluated:

                  Computed Signals work by automatically tracking which other Signals are read during their evaluation. When a computed is read, it checks whether any of its previously recorded dependencies have changed, and re-evaluates itself if so. When multiple computed Signals are nested, all of the attribution of the tracking goes to the innermost one.

                2. 1

                  I’m surprised the proposal does not mentioned events. As events is how I approach the use cases mentioned.

                  Whatever part of the codebase wants to listen to the event that the user selected a new color does this:

                  window.addEventListener(‘userSelectedAnewColor’, userSelectedAnewColor);

                  (All code is in modules, so no namespace pollution. Every module can call the handler function userSelectedAnewColor if it likes to do so)

                  And whoever changes the color does this:

                  window.dispatchEvent(new Event(‘userSelectedAnewColor’));

                  1. 5

                    Seems like the main difference is that signals are pull-based and lazily evaluated. If you change three signals that your UI depends on in the same task, a framework can schedule just one DOM update. Not easy with events.

                    I’d also like to see discussion of prior art like GObject signals and GTK.Expression. (can you tell what I’ve been learning lately?)

                    1. 5

                      Signals were first implemented in a GUI system in Qt 30 years ago (iirc it was the topic of the PhD of one of Qt’s founders), they are built on top of an event posting abstraction like this.

                      After twenty years of this, and extensive work on figuring out the best abstraction for this as a community (for instance through multiple async event loop models experimented in boost.asio) it seems that the consensus is in the sender / receiver abstraction ; which of course had signals & more generally dataflow programming in its designer’s mind: https://intel.github.io/cpp-baremetal-senders-and-receivers/

                      1. 2

                        Events are not a state primitive, though, and because of that you cannot easily perform operations on them.

                        For example, it is non-trivial to write an event which depends on several other events, especially in a general way, meanwhile signals support relatively “standard” operations, like merge/map/filter/reduce/etc (although they do mean slightly different things).

                        Also you can derive “computed” signals, and it is not hard to make them lazily-evaluated compared to events which are pretty much always “hot”.

                        That being said, signals are a different paradigm and I am not sure it is truly necessary to bring them to the standard library.

                      2. 1

                        The functionality to actually listen to a signal, as far as I can tell, is sequestered in the subtle namespace, which is supposed to be for “framework and library developers”. Since signals are effectively just memoized functions without this primitive, I can only assume that this proposal is intentionally useless without a framework.

                        I know why .subtle exists, but it’s still sad to see a standards proposal that treats web authorship as a caste system.

                        1. 2

                          The counter example shows how computed values can be used outside the context of a framework. Can you share a scenario outside of framework development where one would need all the functionality of this proposal where proxies, getters, and setters would not be adequate?

                          1. 1

                            The counter example shows how computed values can be used outside the context of a framework

                            This one? https://github.com/tc39/proposal-signals?tab=readme-ov-file#example---a-signals-counter

                            // A library or framework defines effects based on other Signal primitives
                            declare function effect(cb: () => void): (() => void);
                            
                            1. 1

                              Oh no! I glossed that line! Sorry. That’s too bad.

                        2. 1

                          Signals are a nice abstraction, but they can’t encode cycles so they are a more limited tool than I would like.