Skip to Content

Data

data declares read-only data: the declaration is the instance, deeply immutable, fully validated at compile time. A good fit for data written directly into code: config tables, tuning values, static atlas descriptions.

One Name, Two Roles: Type and Value

public data Item { label: "text", } public data Sword { ...Item, name: "iron sword", atk: 10 + 5, tags: ["iron", "starter"], } func main() -> int { print(Sword.name, Sword.atk); print(Sword.label); return 0; }
iron sword 15 text
  • In type position, Sword is a nominal type; in value position it is the canonical instance. Entries are comma-separated and support constant arithmetic folding (10 + 5 yields 15) and frozen lists.
  • ...Base spreads another data declaration.
  • Entries are separated by commas; the trailing comma before } is optional.

Literals in Expression Position

A data { ... } written in expression position is a runtime literal section, likewise frozen on construction, which suits assembling one-off data locally:

val d = data { x: 5, y: 6, label: "local" }; val moved = d with { x: 50 }; print(d.x, moved.x, moved.label);
5 50 local

Only a data at the start of an expression followed by { is a literal; everywhere else data remains an ordinary identifier.

with: The Only Mutation Channel

Every mutation surface of a data value is closed off; the only way to change the data is to derive a new value with with:

val upgraded = Sword with { atk: 99 }; print(upgraded.name, upgraded.atk, Sword.atk);
iron sword 99 15

The original Sword is unchanged: with produces a brand-new frozen instance. When you need a mutable copy, ToMutable() on a frozen container is the only escape hatch: it converts to the matching mutable container type, and the original data is unaffected:

var mut = Sword.tags.ToMutable(); mut.Add("new"); print(mut.Count, Sword.tags.Count, Sword.name);
3 2 iron sword

Value Domain

Entry values accept: the literal family, enum / flags qualified-name constants, nested anonymous records, frozen lists, references to other data, and vector construction folds. Rejected: null, non-constants, function values and mutable references, class / struct instances.

Notes

  • The name declared by a data declaration cannot be newed: instances come only from the canonical instance slot and with derivation.
  • A data { ... } in expression position is a runtime literal section, frozen on construction, suited to local assembly.
  • Every data value implicitly widens to the built-in supertype Data.
Last updated on October 11, 2026