# Reax Reax is a reactivity system for Rust that infers dependencies between functions. Every `Variable` managed by reax is a node in a dependency graph. Changes to and usages of variables are tracked by the global `ThreadRuntime` which updates the graph to reflect actual variable accesses. There are two kinds of built-in variables: - `Var` which can be explicitly mutated. - `ComputedVar` which lazily computes its value with a function. Users can listen to and react to changes of variables using `.watch`. Critically, *a `ComputedVar` will only re-compute when needed*. If, when computing its value, a `ComputedVar` uses any other variable anywhere (directly or indirectly), changes to any of those upstream variables will automatically mark the computed variable as dirty and the variable's value will be recomputed the next time it is used. ## Examples Reax builds a model of how the variables in your program interact as it runs. ```rust use reax::prelude::*; // Create input variables. let number = Var::new(1).with_label("number"); let name = Var::new("Sam").with_label("name"); // Create computed variables. let formatted = (&number) .map(|x| format!("{}", x)) .with_label("formatted"); let printout = computed! { output! text = String::new(); // Reuse a buffer text.clear(); *text += *name.get(); *text += " sees "; *text += formatted.get().as_str(); }.with_label("printout"); // The computed variables haven't been used yet. Nothing is hooked-up. assert_eq!(printout.node().depends_on(formatted.node()), false); // Use the variables! assert_eq!(printout.get().as_str(), "Sam sees 1"); number.set(42); name.set("Reax"); assert_eq!(printout.get().as_str(), "Reax sees 42"); // Reax now knows how data moves through the variables! assert_eq!(printout.node().depends_on(formatted.node()), true); // Print a .dot visualization. reax::ThreadRuntime::write_graphviz(std::io::stdout().lock()).unwrap(); ``` We can see this example through reax's eyes: ![Dependency Graph](https://gitlab.com/samsartor/reax/raw/master/images/printout_rt.svg) ---- Reax will only update computed variables when needed. ```rust use reax::prelude::*; let number = Var::new(0); let bigger_number = (&number).map(|x| *x + 10); let even_bigger_number = (&bigger_number).map(|x| *x + 100); let times_called = Var::new(0); // Set up a watcher to track how often bigger_number changes. let mut eval = EagerCompute::new(()); eval.watch(&bigger_number, |_| { *times_called.mutate() += 1; }); // The watcher is called once on creation. assert_eq!(*times_called.get(), 1); // Run the watcher. This is effectively a no-op since nothing has changed. for _ in 0..100 { eval.tick(); } // Update a variable. number.set(1); // Dependent variables are instantly dirty. assert_eq!(bigger_number.node().is_dirty(), true); assert_eq!(even_bigger_number.node().is_dirty(), true); // Run the watcher again. This time it fires. eval.tick(); assert_eq!(*times_called.get(), 2); // even_bigger_number is still dirty since no one has used it yet. assert_eq!(even_bigger_number.node().is_dirty(), true); ``` Here you can see how the variables downstream from `number` are all instantly marked when it changes. But they won't be recomputed until used: ![Dependency Graph](https://gitlab.com/samsartor/reax/raw/master/images/bigger_number_rt.svg) ---- Reax has no built-in understanding of collections so you can use nested `Var`s to better control the "depth" of changes. ```rust use reax::prelude::*; // Create a list of variables. let list = Var::new(Vec::new()); for x in 1..=3 { list.mutate().push(Var::new(x)); } // Some computed properties: let length = computed! { list.get().len() }; let sum = computed! { list.get().iter().map(|elem| *elem.get()).sum::() }; // Make length and sum outdated by pushing an extra element. list.mutate().push(Var::new(4)); // Update the length. length.check(&mut ()); // Now only make sum outdated, and leave it that way. list.get()[0].set(100); ``` Visualizing the runtime at the end of this example, you can see that only the sum is dirty. None of the list elements are dependencies of the list itself so any changes to them don't effect variables that never read them. And reax hasn't seen that the extra element will be used in the sum. It will find that out the next time the sum is computed. ![Dependency Graph](https://gitlab.com/samsartor/reax/raw/master/images/list_rt.svg)