&[T] Is a Type of This Language, and It Is What a Run Crosses AsStatus: Accepted
Date: September 21, 2026
Answers: the former open-decisions.md’s may a build-time
value cross as a view into what the build allocated — Option A
Supersedes in part: ADR-302 D5’s &[T] is refused outside an
extern "C" declaration. The &mut half of that sentence stands; the run does
not
Related: ADR-184 D1, D3 and D4 (the run is spelled
ref Array[T]), ADR-311 D1 (a Vec[T] crosses in its view form), ADR-152 (Array[T, N], the
form that was built instead and carries a length),
ADR-094 D1 (the & a caller does not write) and D3 (the mut
that is a declaration), ADR-282 D7 (no copy the program did not
write), ADR-177 (a grammar’s result, and the sub-program that
builds it)
ADR-311 D1 says a build-time result crosses in its view form.
Text has a view type (ref String), and a list can cross as an
Array[T, N] (ADR-152) — but an Array[T, N] carries its length
in its type, so a field of a struct can be one only where every value of
that struct has a run of the same length. struct Section { settings:
Vec[Setting] } is the shape both corpus grammars produce: Array[Setting, N]
cannot type a field whose N differs per value, and a Vec owns memory a
const cannot hold. What is missing is a view of a run whose length the value,
not the type, carries.
Two more things want the same type. A binary asset has no result type an
asset_bytes could have (ADR-310 reads text and refuses bytes
that are not UTF-8), and Bytes (ADR-283 D19) owns its run. Three
absences, one type.
And the type already exists at the C boundary. ADR-302 needs
a run for an extern "C" declaration, where it lowers to an address beside a
count, and refused it everywhere else on the reasoning that a run of elements
whose length the type does not carry has no lowering here. That is true of a
declaration and never of a view: a view of text is exactly such a run.
&[T] is a view of a run, and it is a type wherever a type may stand.Changed by ADR-184 D3 and D4: the run is spelled ref Array[T]; & is not in the language, and only the spelling moved.
It lowers to Rust’s own &[T], a fat pointer that carries its length — which
is the half a Vec and an Array[T, N] also carry and a C declaration does
not. .len(), xs[i], xs[i].field and for x in xs read one.
Two writers for one spelling, which is the arrangement
ADR-302 chose: inside an extern "C" declaration ref Array[T] is
an address beside a count, and everywhere else it is Rust’s &[T]. ref mut
Array[T] and ref mut T stay the boundary’s alone, refused with NK1158 — a position this language may write through is
declared mut name: T (ADR-094 D3), and that half of ADR-302 D5
is not touched.
A ref Array[T] points at a run somebody else keeps. A Vec[T] a body just built is
not one, and there is no & the compiler may write for it: a struct outlives
the expression that fills it, so the view would point at something already gone
(ADR-282 D7 — no copy and no borrow the program did not write).
A parameter is the case where the & is the compiler’s
(ADR-094 D1): the callee reads and the caller keeps, so
total(xs) for an xs: Vec[i64] needs no word, exactly as count(dna) does
for a String against a ref String. The two look identical on the page, which is
why the other one is NK1179 and not a fit that quietly holds.
And the value is spelled against the declaration. The same computed list is
[1, 2, 3] against an Array[i64, 3] and a view of it against a
ref Array[i64], and
nothing in the value says which — so the crossing walks the type beside it,
down through a struct’s fields and a variant’s payload, and writes the &
exactly where a slice was declared.
A grammar runs by compiling the parser it generates (ADR-177 D1),
and a parser builds a Vec. So in the sub-program every ref Array[T] field is written
back as the Vec[T] it is a view of, and the dump — generated from the
program’s declaration — reads a run either way.
That is the crossing rather than a disagreement: the sub-program is ADR-311 D1’s growable side and the program is its fixed one, which is the record’s own sentence read at two ends of one build.
The same rule as D2, at the one place where this checker knows nothing about the
value: an action’s bindings come from the parse. So inside an action anything
that is not already a view is NK1179, and the way out names Vec[T] — because
write a ref is not a thing anybody can do on a grammar line.
What a rule may hand back is the run itself, and that is the crossing the
corpus wanted: entry rule file -> Vec[Setting] reaching
comptime SETTINGS: ref Array[Setting].
Vec[T] arrives as
ref Array[T]; Array[T, N] stays what a program writes where it wants the
length in the type.ref Array[u8] follows for free, which is the byte buffer.NK1179 is the refusal of D2 and D4, and NK1158 covers only the mut
half of ADR-302 D5.std has one impl for it, Get for [V], because [V] is neither a Vec<V>
nor a [V; N] to the language below and a blanket one would overlap the map’s.asset_bytes. The result type exists and the read does not;
ADR-310’s three-part naming is what it would be written under,
and that is a package rather than a line.ref Array[T] handed out of a function is NK2303’s question the way a
ref String is, and nothing here changes that.Section holding a Vec at run time and
crossing as a const is the Tethered representation, not this. What this
gives is the choice between the two forms, written down in the declaration.Bytes (ADR-283 D19), which owns its run and is the same
question read from the other end.