State
State
Classes have a built-in change notification system. A field marked [state]
reports its own changes to the object that owns it, so a class can react when its
data moves rather than having every caller remember to tell it.
on_state_changed
Every class inherits on_state_changed from the root object type:
[public] fn on_state_changed(name: string) {
}The default does nothing. A class overrides it to react, and receives the name of the attribute that changed:
class Document {
[state] title: string
[state] body: string
constructor() {
this.title = ""
this.body = ""
}
fn on_state_changed(name: string) {
io::println(`${name} changed, redrawing`)
}
}What counts as a change
The callback fires when a [state] attribute is modified. That covers the
direct forms:
document.title = "next" // assignment
document.count += 1 // compound assignmentand it covers mutation through a method. A method that assigns to an attribute of
this is a mutating method, which the compiler infers, and calling one reports
the change the same way a direct assignment does.
This is why mutation inference matters beyond bookkeeping: it is the signal the state system is built on. A method that mutates is known to the compiler, so the notification happens without the method having to raise it by hand.
Using it
The pattern suits anything that has to stay in step with its own data: a view that redraws, a document that marks itself unsaved, a model that revalidates. The callback receives the attribute name, so one override can branch on which field moved rather than needing one hook per field.
Keep the work inside on_state_changed short. It runs on every change, including
each step of a loop that assigns repeatedly.
It does not fire inside a constructor, since the object is not finished being
built, and it fires only for attributes marked [state]. A plain field is
ordinary storage.