Repository navigation
Reference subscripts
Mirrored from docs/reference/subscripts.md in the repo — that is the canonical source; edits to this wiki page are overwritten when the wiki is re-synced.
Thesis context: A subscript is the one limited-reference construct that fits the arena + deep-copy model (see the limited-references spike). It generalizes the built-in
&m[k]place: a scoped, transient projection into part of a value — never a stored reference, never crossing the deep-copy thread boundary, needing no lifetime analysis. It is the lvalue/place machinery Tycho already has, exposed to user code.
A subscript names a reusable, zero-copy place into one of its arguments. It does not
return a value — it yields a projection:
struct Node:
weight: int
struct Graph:
nodes: [Node]
subscript edge(g: Graph, i: int) -> inout Node:
yield &g.nodes[i]
fn main():
g := Graph([Node(1), Node(2)])
g.edge(1).weight = 10 # write in place through the projection — no copy
w := g.edge(0).weight # read through it
bump(&g.edge(0).weight) # a field of the projection as an `inout` argument
g.edge(i) is not a function call. At compile time it is replaced by the yielded place with
the arguments substituted (g.nodes[i]), then the surrounding read or write flows through
the ordinary place machinery. There is no runtime object — a subscript is a compile-time
place-macro, the exact analog of the built-in &m[k].
subscript <name>(<recv>: T, <params>...) -> inout U:
yield &<place>
- The body is a single
yield &<place>, where<place>is a field/index spine (g.nodes[i],r.cells[i],p.tags[0].x, …). -
-> inout Uis the type of the projected place; it must match the yielded place's type. - Called as a method on the first parameter:
recv.name(args). The receiver's type selects the subscript.
- Rooted in a parameter. The yielded place must be rooted in one of the subscript's parameters — it projects into an argument, so it cannot dangle. A place rooted in a fresh local is rejected.
- Each parameter used at most once in the yielded place, so an argument is never double-evaluated when substituted. (Multi-use with argument hoisting is a future extension.)
-
Value semantics is unchanged. A projection is a place into a value you already own or
borrow; the usual mutability rules apply (writing through a projection into a by-value
parameter mutates that parameter's private copy, exactly like
g.nodes[i].w = …spelled out). A projection is scoped and transient — it is never stored in a field and never sent across aspawn/channel boundary. That is what keeps it compatible with the arena model.
Subscripts do not let you store a graph by reference. They make traversing an
index-pool structure ergonomic (g.edge(i).w = … instead of g.nodes[i].w = …, and reusable
accessors over composite storage); they are convenience over the index-pool idiom, not a new
storage shape. Storing a reference (a "remote part") is a decided non-goal — it has no sound
deep-copy at the thread boundary. See the limited-references spike.
The reader docs here are mirrored from /docs in the repo — the canonical source. · tycho-lang.com · MIT licensed
- Tutorial
- The Tycho thesis: value semantics makes implicit arenas work
- Architecture & project status
- From
mallocto implicit arenas
- Tycho language reference
- Basics
- Types
- Functions and closures
- Structs and tuples
- Enums, options, and
match - Arrays and slices
- Subscripts (user-defined projections)
- Maps
- Generics
- Concurrency
- FFI (calling C)
- Packages
- Builtins
- Memory model in the self-hosted compiler
- Tycho aggregates: arrays & structs under value semantics
- Maps with arbitrary value types
m[k]as a place: in-place map-value mutation- Generics (monomorphized)
- Concurrency in Tycho
- FFI — calling C from Tycho
- Packages & modules
- corelib — Tycho's standard library
- Performance: the self-hosted transpiler vs the C one
- Debugging generated C