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).
It's Mico (without an r), now I guess it's not a good name (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)
)
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).
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.
@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. 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).