Skip to content

API Reference — Tag Identity and Slot Programming

Two rules run through the whole API. Tag identity: what a handle is. Slot rule: where it lives.


Tag identity — class, not instance

PolyHelper(T) generates one static _tag: PolyTag per type T at comptime.
TAG is a pointer to that static — the same address for every instance of T.

Tag dispatch (is_it_you, isIt, fromPoly) answers one question: "is this a T?"
It does not answer: "which T?" or "what role does this T play?"

For user-defined types (Event, Sensor, etc.):

  • Tag identifies the class.
  • Instance fields carry the role. The user adds a kind or role field to discriminate.

For infra handles (Mbox, Pool):

  • Mbox and Pool are public structs, but their fields are internal. The user cannot add fields.

  • Tag identifies the class only. No per-instance role information is accessible.

  • Instance identity: resolved by pointer comparison. E.g. Mbox.mustFromPoly(slot.?) == worker_mbx identifies which specific
    mailbox arrived, comparing two *Mbox.

  • Role: established by protocol — the channel the handle arrived on, message ordering, or prior agreement between sender and receiver.


Transporting infra handles — valid patterns

Worker-finish-signal pattern

Master creates worker_mbx, spawns a worker via io.concurrent and passes worker_mbx as parameter.
Worker processes items until a shutdown signal, then:

  • Sends worker_mbx.toPoly() back to master's inbox (unclosed) as the finish signal.
  • Exits.

Master receives a PolyNode from its inbox:

  • Mbox.mustFromPoly(slot.?) — crosses the border, panics if the node is not a mailbox. Mbox.fromPoly is the checking form, null on mismatch.

  • Mbox.mustFromPoly(slot.?) == worker_mbx — confirms instance (it is the expected worker mailbox). Both sides are *Mbox.

  • Master closes and destroys worker_mbx.

  • Master awaits the worker's future (cleanup only — the mailbox return was the logical finish signal).

This pattern replaces relying on the future await as a completion signal, or a separate shutdown message, with a handle handoff.

Wrapper pattern (for tag-level role discrimination)

When tag dispatch must distinguish roles, wrap the handle in a user-defined PolyNode struct:

const WorkerInbox = struct {
    poly: PolyNode,
    mbx: *Mbox,
};
pub const WorkerInboxPolyHelper = polynode.PolyHelper(WorkerInbox);

WorkerInboxPolyHelper.TAG is distinct from Mbox.TAG.
The receiver dispatches on WorkerInboxPolyHelper.TAG and finds the embedded *Mbox.