Skip to content

Templates and Aliases

phroun edited this page Aug 22, 2026 · 2 revisions

The wire language has two ways to stop repeating yourself. Both are declared in the same request as the objects that use them, and both live for the life of the connection.

  • template — a named type with properties and children built in.
  • alias — a short name for a property name.

Neither adds a runtime concept. A template expands at instantiation into the builtin type it is built on, so the display service ends up with exactly the objects you would have written by hand.


Templates

template FormRow=panel layout=hbox spacing=8
new FormRow children={ new label caption="Name:"; new textinput stretch=1 }
new FormRow children={ new label caption="Email:"; new textinput stretch=1 }

template Name=base props… declares it. The base is a builtin type, or another template. Everything after the base is applied to each instance before that instance's own properties.

Instance properties override the template's

template MyBtn=button align=right caption="Click Me" visible
new MyBtn caption="Other" !visible

The object receives align=right, caption="Click Me", visible, and then caption="Other", !visible. Later wins, so the instance's caption and its un-set of visible are what survive. This is ordinary property ordering, not a special merge rule.

Templates chain

A template's base may be another template, to any depth:

template Plain=button caption="OK"
template Danger=Plain fg=bright_red
new Danger

Danger is a button with both properties. The chain is accumulated base-most first, so the more specific template wins where they disagree. A cycle is refused rather than followed.

Templates can carry children

template LabeledInput=panel layout=hbox children={
	lbl=new label caption="?"
	input=new textinput
}

Template children come first; an instance's children are appended to them, not substituted for them:

template LabeledInput=panel layout=hbox children={
	lbl=new label caption="?"
	input=new textinput
}
row=new LabeledInput children={ new label caption="extra" }

builds a panel with three children — the template's label, the template's text input, then the instance's label.

Reaching inside an instance

Keys written inside a template body are namespaced under the instance's key, and you surface the ones you want with key=path:

template LabeledInput=panel layout=hbox children={
	lbl=new label caption="?"
	input=new textinput
}
row=new LabeledInput
field=row.input
cap=row.lbl

The reply carries row, field and cap — the panel, the text input, and the label. Keys you do not surface stay internal to the instance and are not returned, so a template can have as much private structure as it likes without every instance handing back a pile of ids.

Templates settle the property ordering

A property that indexes children has to come after them (see ListView). Within one statement that ordering is the author's to get right. A template applies its children before any instance's properties, so the ordering holds at every use:

template Sizes=listview children={
	new item caption="Small"
	new item caption="Medium"
	new item caption="Large"
}
lv=new Sizes selected=2

selects the third row. The same ordering applies inside the template —

template Bad=listview selected=2 children={new item caption="A"; new item caption="B"}

— and that fails as silently as it does anywhere else, so keep a template's own arguments in order too.

Aliases

alias C="caption" V="visible"
new button C="Aliased" !V

alias Name="target" is a lexical macro for a property name, and nothing else. The target is a quoted string, and substitution happens where a property name is expected.

An alias is not a value, a type, or an object. It cannot stand in for a children block, a type name, or a property's value — which is what a template is for.

Naming

Both obey the same rule: user-declared names begin with an uppercase letter, builtin type and property names are lowercase. That is what makes substitution unambiguous — a lowercase word is always the protocol's, an uppercase one is always yours.

The rule is enforced, and the errors say so:

Written Result
template lowercase=button rejected — templates must begin uppercase
alias c="caption" rejected — aliases must begin uppercase
alias C=caption rejected — an alias target must be a quoted string
new button X="boom" rejected — X is not a declared alias
template Orphan=Missing rejected — unknown base template
new Undeclared rejected — unknown template

A correlation key does not apply to either verb: k=template … is an error, because a declaration creates no object to correlate.

Scope

Templates and aliases belong to the connection, and last as long as it does. They are not global, so two applications — or two connections from one application — cannot collide on a name.

Declare them in the same request that uses them, or in an earlier one on the same connection; both work, since the session remembers.

See also

Object Model — the new / set / destroy verbs · Properties and Values · Panel · ListView

Clone this wiki locally