Signals are Prism’s reactive primitive. A signal is declared once, fired with emit, and
handled with on — exactly the handlers registered for that signal run, nothing else. No
diffing, no virtual DOM, no full re-render.
The basics
signal CountChanged(value: int);
on CountChanged(value) {
println(value);
}
fn main() {
emit CountChanged(0);
emit CountChanged(1);
}
Declare a signal once, subscribe with on, and fire it with emit. That is the entire reactive
surface in v0.1.0.
Carrying data
A signal can carry several values at once. Handlers receive them in order:
signal NameChanged(first: str, last: str);
on NameChanged(first, last) {
println(first + " " + last);
}
fn main() {
emit NameChanged("Ada", "Lovelace");
}
Computed/derived signals are not in v0.1.0 — recompute in the handler instead.
Effects
An on handler is the effect mechanism — it runs every time the signal fires:
signal FullChanged(value: str);
on FullChanged(value) {
println(value);
}
There is no watch in v0.1.0. Handlers are the subscription: this is what makes Prism UI
updates cheap — an update is an emit, and only the handlers registered for that signal run.
Signals in UI
PrismX widgets declare signals that the app loop reacts to:
class Counter {
Label countLbl = {
text = "Clicked 0 times"
}
Button incBtn = {
text = "Increment"
onPress: {
Signal onIncrement()
}
}
}
When the button is pressed it emits onIncrement; a handler updates the label with
setText(id, …). Widget text is a property, updated from the signal handler.
Note: signals are not threads — but they are thread-safe to use.
emitfrom any thread schedules the dependent handlers on the thread that owns the UI.
Batch updates
A batch is just emitting both signals in sequence — there is no batch keyword in v0.1.0:
signal ThemeChanged(value: str);
signal AccentChanged(value: str);
on ThemeChanged(value) { println(value); }
on AccentChanged(value) { println(value); }
fn main() {
emit ThemeChanged("dark");
emit AccentChanged("violet");
}
Next: Memory safety.