Look for feedback on an experimental signal-based framework for frontend app

Hi,
I’ve just made the first commit of an experimental signal-based framework for wasm frontend app. A signal-based framework will execute only the right part of the code in response to a change in your app’s state to update the right part of the view. (While virtual DOM frameworks usually walk through the (almost) whole virtual DOM to find diffs).

Feedbacks are welcome! (Hey, I don’t know to say this more appropriate in English :smiley: )

2 Likes

Quoting rust-signals: What is a Signal? It is a value that changes over time , and you can be efficiently notified whenever its value changes.

On the micro README, you refer to ELM.

Are you building an https://en.wikipedia.org/wiki/Functional_reactive_programming library? Where we create a directed acyclic graph where:

  • for each node, we have a “current value” + a function (in terms of inputs) to be re-evaluated
  • each directed edge = depeendency

whenever something changes, we calculate a topological sort and recalculate the nodes that need to be updated ?

==

If not, can you briefly explain the high level of how your micro/signal system works?

It’s Mico (without an r), now I guess it’s not a good name :smiley: (if I publish on crates.io - still not sure now, I think I should choose a new name).

I actually just know Elm by looking at its examples (never use it, because functional programming make me stupid). So, just stating Elm-like may give many big false impressions. It’s my bad. Originally, I mean the separation of updating (the app state) and rendering (view).

I think it is. May be an example explain better than my words (I am bad in English):

    mico::dom::Div::new()
         // Here `mico` will create a text node and a closure.
         // The closure will be executed when `self.value`
         // changes, updating the content of the text node
         // with the value from `self.value`
        .text_signal(self.value.signal())
        .child(
            mico::dom::Button::new()
                .text("Up")
                 // Register an event that send message
                 // back to the app's `update` method
                .on_click(main, |_| Msg::Up)
        )

I’m sorry, I still can’t figure out if this is a FRP system or not.

Have you seen the animations at http://conal.net/fran/tutorial.htm ? It seems like your “signal” system is very similar.

(I’m trying to compute a ‘diff’ between Mico & FRP to see what’s new and what’s old).

That’s a long article, and because I am not good in English, please give me some time to read it.

Not sure what you as thinking when saying that, but I feel a bit weird reading it. https://github.com/Pauan/rust-signals is the work of https://github.com/Pauan.

In the mean time, you may want to read the tutorial of futures-signals here (it’s not from the latest version, but is still up to date, docs.rs failed to build documentation for the new version).

1 Like

@Pauan

2 Likes

Hi, I’m the creator of futures-signals (though not involved with mico).

Yes, that’s exactly what happens. You create a graph of Signals, and then when something changes it automatically updates the graph (in the most efficient way possible).

Unlike most other FRP systems, my system is extremely fast and light-weight: it is a zero-cost abstraction, similar to Futures. Almost everything is stack allocated.

And it solves some tricky issues that some other FRP systems have: in particular it solves the dichotomy between “hot” and “cold” Signals, and it also solves the diamond dependency problem.

Unlike the old Elm Signals, it allows for dynamically changing graphs (i.e. flatMap). It does this in a way that avoids the problems that Elm ran into.

It’s based on several years that I’ve spent researching and using FRP systems in practice.
I also created a zero-cost DOM library which uses my Signals for very fast DOM updates (it can also do smooth 60 FPS animations with Signals).

However, dominator encourages a more imperative approach, where you create event listeners and then mutate state inside of those event listeners (as shown here).

limira did not like that, they wanted a system similar to Elm where you have three separate parts: state, update, and render. So they created mico to achieve that goal.

It is possible to achieve something similar in dominator, but it is not currently idiomatic to do so. And there are quite a few other differences between dominator and mico.

4 Likes

Thanks @Pauan for the rescue! :heart:

@Pauan : Thanks for the detailed explanation. One more question – if I wanted to build the “core engine” of a VisiCalc/Excel in Rust, with “typed cells”, Signal would be an excellent library for handling the updates right?

@limira : Sorry about hijacking your mico thread into a signal thread. :slight_smile: Do you think you can duplicate the FRAN animations in minimal lines of mico? I think it’d be really cool to see these examples in canvas or svg.

Sure. I imagine a good structure would be something like this (simplified, but gives the right idea):

enum Formula {
    Value(i32),
    Add(Rc<Cell>, Rc<Cell>),
}

struct Cell {
    formula: Mutable<Rc<Formula>>,
}

impl Cell {
    fn value(&self) -> impl Signal<Item = i32> {
        self.formula.signal_cloned().switch(|formula| {
            match formula {
                Formula::Value(x) => Box::new(always(x)),
                Formula::Add(x, y) => Box::new(map_ref! {
                    let x = x.value(),
                    let y = y.value() =>
                    *x + *y
                })
            }
        })
    }
}

(And similarly for other operations, like multiplication, etc.)

By setting things up this way, you create a dynamically changing graph which will automatically update whenever a cell’s value changes, or when a cell’s formula changes.

Everything is handled automatically by the Signals system, so you only need to worry about updating the Mutable whenever the user types into the cell.

And since Formula is recursive (it can refer to other Cells), this means the graph will efficiently update no matter how deep the dependencies are.

The allocations for the Rc and Box are probably necessary, in order to support the fact that the graph can dynamically change.

With some tricks, you might be able to remove the allocations, but I’m not sure if that’s worth it.

I’m happy to talk more about this in a private message (or in an issue on the futures-signals repo).

1 Like

Never mind. I am happy to be the bridge that connects you to futures-signals.

I think Pauan’s dominator is ready for this. About mico, I focus on my personal use first (not involve graphical nor animation).

2 Likes