TOUR · CHAPTER 4

Composing spaces

Independent spaces, composed with $use(). No new syntax — just a directive.

Anglish spaces are independent units. Once you’ve declared one, anyone can compose it into a larger space using a single directive: $use().

A composition example

Here’s a checkout panel built from two independent forms:

@ShippingForm:UI
>>> Form for collecting the user's shipping address.
>>> Bind inputs to %shippingData.
>>> When %onSubmit, delegate to $validateShipping.
>
@PaymentForm:UI
>>> Form for collecting credit-card and billing information.
>>> Bind inputs to %paymentData.
>>> When %onSubmit, delegate to $validatePayment.
>
@CheckoutPanel:UI
>>> Checkout panel that composes the shipping and payment forms.
>>> $use(@ShippingForm)
>>> $use(@PaymentForm)
>>> On %orderSuccess, display confirmation via $ui_writer.

Two things to notice.

Independence. @ShippingForm and @PaymentForm are complete on their own. Nothing in their declarations knows that a @CheckoutPanel exists. They can be tested in isolation, reused in other panels, or version-controlled separately.

Composition without nesting. @CheckoutPanel calls them by name with $use(). There’s no structural nesting required, no inheritance, no mixin syntax — the directive simply imports the named space into the parent.

Subspaces via dotted names

Sometimes you do want a hierarchical relationship. Anglish handles that with dotted identifiers — no new syntax:

@userSettings:UI
>>> Composes the profile and security sub-panels.
>
@userSettings.profile:UI
>>> Form for editing the user's name, avatar, and contact information.
>
@userSettings.security:UI
>>> Panel for updating password and two-factor authentication settings.

The compiler treats the dotted path as a single distributed unit. Subspaces share queues, state, and scratchpads with their parent. When you don’t want sharing, use $use() instead.

Late binding via %data

Here’s the move that makes composition useful: tasks like $saveSettings(in=%data) don’t care which sub-panel called them. The shared task is bound at call time to whatever data resource the caller passes in:

$saveSettings(in=%data)
>>> Persists the incoming settings block (%profileData or %securityData)
>>> to the backend service. Emits %saveSuccess or %saveFailure.

One persistence task, two callers, late-bound data. The compiler verifies the data shapes match at the point of call.

Why this matters for review

When the AI fills in @CheckoutPanel, it cannot rewrite @ShippingForm to suit itself. The shipping form is a named, addressable, hash-pinned space — the audited binary is what runs. This is the difference between “the GDPR redactor in prose” (which the AI helpfully reimplements every time) and $use(@gdpr_redactor_v2) (which it cannot).

Next: review, sign, ship.