flo_binding 0.1.1

Declarative binding library for Rust
Documentation

Bindings

This library provides a mechansim for designing applications with a data-driven control flow. This is essentially the paradigm found in spreadsheets, where a formula will update automatically if its dependencies update. This is a convenient way to express how a user interface updates, as it eliminates the need to describe and manage events.

A simple binding can be created using let binding = bind(X). This creates a simple mutable binding that can be updated using binding.set(Y) or retrieved using binding.get().

This value can be monitored using when_changed, as in let lifetime = binding.when_changed(notify(|| println!("Changed!"))). The lifetime value returned can be used to stop the notifications from firing. Unless lifetime.keep_alive() is called, it will also stop the notifications once it goes out of scope.

So far, this is very similar to traditional observables. What makes bindings different is the idea that they can be computed as well. Here's an example:

# use flo_binding::*;
let mut number      = bind(1);
let number_clone    = number.clone();
let plusone         = computed(move || number_clone.get() + 1);

let mut lifetime    = plusone.when_changed(notify(|| println!("Changed!")));

println!("{}", plusone.get());  // 2
# assert!(plusone.get() == 2);
number.set(2);                  // 'Changed!'
println!("{}", plusone.get());  // 3
# assert!(plusone.get() == 3);
lifetime.done();

number.set(3);                  // Lifetime is done, so no notification
println!("{}", plusone.get());  // 4
# assert!(plusone.get() == 4);

Computed values can be as complicated as necessary, and will notify the specified function whenever their value changes.

Cloning a binding creates a new binding that references the same location. This makes it easier to pass bindings into closures (though still a little awkward as Rust doesn't really have a shorthand way of doing this for philosophical reasons). They're similar in behaviour to an Arc<Mutex<X>> object in this respect (and never really immutable given that cloning them creates a mutable object)

Computed bindings as demonstrated above are 'lazy'. They don't know their own value until they have been evaluated after a change (and start in this 'uncertain' state), so they will not notify of value changes until they have been read at least once and will not notify again until they have been read again. Reading the value from within the notification is possible but in general the idea is to queue up an update for later: being lazy in this way prevents repeated computations of intermediate values when many values are being updated. Knock-on effects are all accounted for, so if a future update is queued, it won't trigger further notifications.