Component Constraints
Component constraint type
The *component[...] type accepts any component that implements specific @dispatch methods:
fn render(widget: *component[@dispatch fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32)]) {
widget.paint(ctx, 0, 0, 100, 100);
}Any component with a matching paint dispatch satisfies this constraint — no explicit implements declaration needed.
The is operator
Use is to check at runtime whether a component pointer satisfies a constraint:
if (widget is *component[@dispatch fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32)]) {
widget.paint(ctx, x, y, w, h);
}The compiler generates vtable slot checks — it verifies that each required dispatch slot is non-null in the component’s vtable.
Type aliases for constraints
The standard library defines type aliases for common constraints:
type Drawable = *component[@tape {drawable();}];
type Layoutable = *component[@tape {layoutable();}];
type Interactive = *component[@tape {interactive();}];These use @tape {} blocks inside the constraint to invoke the same comptime helpers that components use, ensuring the dispatch signatures always match.
Collections of constrained components
fn render_all(widgets: []Drawable) {
for (w in widgets) {
w.paint(ctx, 0, 0, 100, 100);
}
}Multiple dispatches
A constraint can require multiple dispatch methods:
type Widget = *component[
@dispatch fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32);
@dispatch fn handle_pointer(ev: *ui.PointerEvent);
];The is check ANDs all dispatch slot checks — all must be non-null.
Required vs optional dispatch
Within a component declaration, dispatches can be marked required:
component Base {
@dispatch(required) fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32);
@dispatch fn layout(ctx: *u8, x: i64, y: i64, w: i64, h: i64);
}A @dispatch(required) must have a corresponding method implementation — the compiler errors if the method is missing.
How dispatch works
Each component gets a vtable — a table of function pointers indexed by global dispatch ID. The compiler:
- Assigns a global ID to each unique dispatch name + signature
- Generates a vtable per component with slots for its dispatches
- Emits indirect calls through the vtable for dispatch method calls
- For
ischecks, loads the vtable and verifies the required slots are non-null
Structural, not nominal
Constraints are structural — they match based on dispatch signatures, not names or explicit implementations. Two components with the same paint signature both satisfy Drawable, even if they were written independently.
Last modified: