[HN Gopher] The Missing Manual for Signals: State Management for...
___________________________________________________________________
The Missing Manual for Signals: State Management for Python
Developers
Author : buibuibui
Score : 70 points
Date : 2025-06-13 11:55 UTC (11 hours ago)
(HTM) web link (bui.app)
(TXT) w3m dump (bui.app)
| rikafurude21 wrote:
| I've been writing front-end javascript the "just use functions"
| way and never really wanted to get into React because it looks
| too complicated. But this makes sense. God damn it I want to
| actually learn react now.
| troupo wrote:
| React is very far from signals (and very far from sane state
| management). Better alternatives:
|
| - SolidJS (kickstarted the whole signals revolution)
|
| - Svelte
|
| - Preact (and Preact Signals)
|
| - Well, even Angular got signals now
| aquariusDue wrote:
| There's also Datastar that uses signals and ends up being the
| best of HTMX and Alpine.js combined (at a smaller bundle size
| too).
|
| https://data-star.dev/
| lbreakjai wrote:
| React doesn't really make many assumptions regarding state
| management. You're free to pick the library you want. Redux
| used to be the standard, but I worked on applications purely
| using RxJS, the way signals are presented in this article.
| troupo wrote:
| > You're free to pick the library you want.
|
| They are all still pretty hampered by React's model: re-
| render (internally, in VDOM) the whole component on any
| minor change.
| buibuibui wrote:
| I actually created the library after being exposed to Angular
| Signals starting from the v16 release. I watched some talks
| and read articles about Signals, just to know about Ryan
| Carniato from SolidJS. He did an excellent job teaching the
| world about Signals!
| jazzypants wrote:
| This article never mentions React. This has nothing to do with
| React. There's a reason people say "react is not reactive"[1].
|
| Signals are derived from Observables[2] which were first used
| in Adam Haile's S.JS[2] and made popular in JavaScriptLand by
| Ryan Carniato's SolidJS[3].
|
| [1] - https://dev.to/this-is-learning/how-react-isn-t-reactive-
| and...
|
| [2] - https://dev.to/this-is-learning/the-evolution-of-signals-
| in-...
|
| [3] - https://www.solidjs.com/
|
| [4] - https://github.com/adamhaile/S
| WesolyKubeczek wrote:
| > made popular in JavaScriptLand by Ryan Carniato's
| SolidJS[3]
|
| Are you sure it hadn't been, by chance, made popular even
| before by KnockoutJS?
| troupo wrote:
| Actual popularity to the point that they are now being
| adopted into the standard (not to say _all_ frameworks
| except React) came thanks to Ryan. Though he explicitly
| acknowledges that original ideas come from Knockout, S and
| Marko
| jazzypants wrote:
| Yeah, as I said in response to another commenter, I
| actually had a link to Knockout in my clipboard. I'm pretty
| sure I was supposed to add the link after the word
| Observable.
| jauco wrote:
| Fwiw knockoutjs seems to predate s.js (2010 vs 2013)
|
| I can't remember if at that point it was the first lib to
| uses observables.
| jazzypants wrote:
| Oof! I can actually still see a link to Knockout.js in my
| clipboard, so I clearly meant to add it as a source for
| that post. I also got the numbering all wrong, so I guess I
| should have spent another minute checking it for accuracy.
|
| Thanks for the correction so that other people can learn!
| Izkata wrote:
| Since GP mentioned React, I think MobX was more popular there
| and seems to predate SolidJS. Also, Valtio is a modern
| version of the same idea but with a lot less boilerplate.
| yapyap wrote:
| look into the Java observer pattern
| esafak wrote:
| For bigger workflows, this declarative pattern is already
| implemented by orchestrators like Dagster, Flyte, and recently
| Airflow; e.g., https://dagster.io/blog/declarative-scheduling
| [fixed]
| ycombiredd wrote:
| this 404's for me
| jpitz wrote:
| Are you talking about Airflow Datasets and data-aware
| scheduling?
|
| https://airflow.apache.org/docs/apache-airflow/2.4.0/release...
|
| Isn't that about as recently as Dagster?
| twic wrote:
| y = Computed(lambda: calculate_y(x()))
|
| How does this instance of Computed know that it depends on x?
| Does it parse the bytecode for the lambda? Does it call the
| lambda and observe which signals get accessed?
|
| In my homebrew signal framework, which emerged in the middle of a
| complicated web dashboard, this would look like:
| y = Computed([x], calculate_y)
|
| So the machinery gets to see the signal directly.
| buibuibui wrote:
| I am using the standard Python library `contextvars.ContextVar`
| as the foundation of my reactivity system's dependency tracking
| mechanism. In the computation step, when Signals get accessed,
| I track them as dependencies.
| TOGoS wrote:
| I've used systems that did this (some TypeScript TUI library
| comes to mind) and was similarly confused. I think what
| actually happened was that the x function/getter/whatever had
| some 'magic' in it that let it communicate with `Computed` as a
| side-effect of `Computed` computing the value.
|
| Too magical for me. I'd rather have something like you
| described where inputs are explicit, so I don't have to guess
| about whether the magic will work in any given case.
| TeeMassive wrote:
| The module probably has its own global register and ever time
| Computed() is called it adds to it.
| jacques_chester wrote:
| This triggered some associations for me.
|
| Strongest was Cells[0], a library for Common Lisp CLOS. The
| earliest reference I can find is 2002[1], making it over 20 years
| old.
|
| Second is incremental view maintenance systems like Feldera[2] or
| Materialize[3]. These use sophisticated theories (z-sets and
| differential dataflow) to apply efficient updates over sets of
| data, which generalizes the case of single variables.
|
| The third thing I'm reminded of is Modelica[4], a language where
| variables are connected by relations (in the mathematical sense).
| So while A = B + C can update A on when B or C change, you also
| can update just A and B, then find out what C must have become.
|
| [0] https://cells.common-lisp.dev
|
| [1]
| https://web.archive.org/web/20021216222614/http://www.tilton...
|
| [2] https://www.feldera.com
|
| [3] https://materialize.com
|
| [4] https://modelica.org
| mananaysiempre wrote:
| > Strongest was Cells[0], a library for Common Lisp CLOS. The
| earliest reference I can find is 2002[1], making it over 20
| years old.
|
| How about Microsoft DirectAnimation[1] from 1998, literally
| designed under the direction of Conal Elliott? Serious
| question, for what it's worth, I've always wondered if all
| discussions of this thing are lost to time or if nobody cared
| for it to begin with.
|
| [1]
| http://sistemas.afgcoahuila.gob.mx/software/Visual%20Basic%2...
| PaulHoule wrote:
| ... or Visicalc, TK/Solver, etc.
|
| I've always been baffled that people think spreadsheets are
| like dataframes when the really interesting thing has always
| been you can write formulas that refer to each other and the
| engine figures out the updating. Most of the times I've
| written a spreadsheet I haven't used the grid _as a grid_ but
| just a place I can write some labels, some input fields and
| formulas.
| cdavid wrote:
| well it is both an easy way to compute in a dataframe
| context and a reactive programming paradigm. When combined,
| it gives a powerful paradigm for throwing data-driven UI,
| albeit non scalable (in terms of maintenance, etc.).
| awkii wrote:
| What the author touches on with before and after "declarative
| thinking" is largely applicable to all Directed Acyclic Graph
| (DAG) workflows, and not just signals. They are 100% correct that
| there is a mental shift. Yes, you can use magic to implicitly
| declare your DAGs with signals. You can also be really explicit
| with dependencies.
|
| DAG-based workflows incur a cost in terms of complexity, but
| there are a few advantages to using DAGs instead of sequential.
|
| 1. Parallelism becomes inherently built-in
|
| 2. It's easier for a new developer to understand the direct
| dependencies of a node on other nodes (compared to sequential).
| Sometime in the future, a developer may want to split off a task
| or move it up/downstream of other tasks.
|
| 3. Fault tolerance & recovery becomes easier. Just because 1 step
| fails, doesn't mean that the whole workflow must come to a halt.
| coldtea wrote:
| What makes signals DAG?
|
| User caution or does e.g. this lib prevents cycles?
| HelloNurse wrote:
| Two perplexing aspects:
|
| - Why so many lambda functions instead of regular named
| functions? Is it a technical limitation? Something important
| should have a name, for instance (for the example in the article)
| different ways to compute greetings from names.
|
| - How are the computations ordered, particularly multiple Effects
| that trigger at the same change? For instance, in the example in
| the article, when the name changes the updated greeting is
| printed before or after the updated location.
| buibuibui wrote:
| You can use normal names function instead of lambdas if you
| prefer! In Javascript anonymous functions are used normally for
| things, where defining named functions are considered too
| verbose - I use lambdas for that in Python.
|
| The Signals evaluation are topologically ordered and are
| running synchronously. Effects are running in the order they
| are defined.
| weiliddat wrote:
| Hmm I have mixed feelings about this. I've thought about this
| topic for a bit, a couple of years ago I thought of bringing
| functional reactive programming to a backend node.js project
| (partially because of managing callback hell); in the past couple
| of years I work on an event/workflow system with 100+ million
| events per day.
|
| This feels like a lighter weight alternative to Temporal or other
| workflow tools[0], but eventually for a backend system you'd
| likely be rebuilding features that are tailored for the backend.
|
| In frontend code, you have many side effects (e.g. DOM, styling)
| that rely on a single piece of data/event, and more side effects
| that rely on those side effects (e.g. component hierarchy), and
| having this laid out declaratively is one way to understand the
| behavior of an application when this piece of data changes. You
| are also almost never concerned about durability/persistence of
| the state of data on the frontend, just because the code
| interacts with the browser and we almost never question the
| reliability of that API. A human is typically the "driver" of
| these interactions and is typically in the loop for most
| interactions, so stuff that fails, e.g. a failed network call,
| can bubble up to the user to deal with.
|
| Conversely, web backend projects have code and infrastructure
| that are distributed (even monolithic ones), and most of the time
| are concerned with persisting state/data, distributing/scheduling
| workloads, etc. Each side effect / computation, especially ones
| that cross networks/service, has its own requirements for whether
| it should be at least once/at most once, retried/retry patterns,
| latency/throughput, failure modes/error handling. These
| requirements also define your boundaries/interfaces, rather than
| a nice semantic and declarative one (not exclusive but oftentimes
| the requirements win out).
|
| Not saying that this signal-based approach can't be used in some
| areas of the application would benefit for declarative
| computation, but the examples given seem to indicate also a
| desire to do distributed workflow stuff.
|
| [0] https://temporal.io/, https://github.com/meirwah/awesome-
| workflow-engines
| cdavid wrote:
| One of the largest, if not the largest python codebase in the
| world, implements similar ideas to model financial instruments
| pricing: https://calpaterson.com/bank-python.html.
| pvillano wrote:
| I have a dream for a compiled reactive DSL for video game
| programming that makes replay and rollback netcode automagically,
| eliminates bugs in state management, and naturally expresses
| derived state and the simulation step/transition function, while
| still being performant enough for real time
|
| The performance hit from all that indirection of registering,
| getters, setters, discover, traversal, and lambdas could be
| avoided if we could compile the dag into smartly nested ifs
___________________________________________________________________
(page generated 2025-06-13 23:01 UTC)