ref X, and Text Has One NounStatus: Accepted
Date: September 21, 2026
Supersedes the spelling of: ADR-282 (&str as the assertion
that it is a view), ADR-094 D2 (&T), ADR-302 D5
(&mut T, &[T]), ADR-179 D1 (&[T]). None of their
decisions changes — only the characters they are written with
Related: ADR-298 (the reserved words), ADR-296
D2 (the generated file says what the program said), ADR-152 D4
(an array carries its length)
Most &s in the corpus were a type spelling, most of those &str, and few a
borrow a program writes by hand, because ADR-094 D1 already made
a parameter the body only reads a view without the word.
So the character a reader meets most is not a borrow operator at all. It is
part of &str, and &str is the one place this language has two nouns for
one type: text is String (ADR-282), str is not a type a
program may write anywhere else, and that record had to explain the gap in
prose — &str is the assertion that it is a view.
The assertion can be a word instead. That is the whole of this record.
ref X is a view of an X, and is written only in extern "C".Changed by ADR-views-3 D4: ref X stands only inside extern "C"; elsewhere a view is inferred (D5, D8) and a written ref is refused.
Inside an extern "C" block, ref T and ref mut T say that a foreign
function takes a view; that is the one place the word stands. Everywhere else
a parameter is lent unless it says mut or keep, a view in a field, element
or let is inferred, and a result’s source is inferred or written from
(ADR-views-3 D2-D5, D8); a written ref there is refused.
One word, one meaning, in one place.
It is reserved (ADR-298’s list gains its thirty-seventh
word), and the corpus is not what decided it. Counting ref over every .nika
file gave zero uses — which says the word is free, and it is not: a call
written ref(x) is a borrow of (x) to the grammar and a call to a function
named ref to its author, in the same characters. A word that is a name in one
position and an operator in the next is worse than a reserved one, because the
reading nobody meant is the silent one, which is
ADR-010 D1’s polarity.
A count over the corpus cannot see a collision the corpus does not write; a
program that writes each word in every position a name may stand can, and
ref(x) is what it finds.
str is not a name the language has.ref String is what a program writes and what a message prints. str stays
the compiler’s word for a view of text, because the language below spells
it that way and the emitter writes name for name (ADR-296 D17) —
but it does not reach a program, a signature, a ledger or a diagnostic.
Normalised at both doors and not at one. A type arrives from the AST
(Ty::from_ast, what a signature declares) or from text (Ty::parse, what a
ledger carries), and a view of String becomes the text view in both. With it
in only one, the checker would hold ref String and ref String as two
types and print one spelling twice claiming they differ.
Array[T] is an array of any length, and the position says where the length comes from.Changed by ADR-views-3 D11: a lent or mut parameter Array[T] is a view of a run, and the parameter generic over its length stays for keep; a field, element or result Array[T] is a view where a piece of a buffer flows in, else NK1182 with Vec[T] and Array[T, N] as ways out; the “under a ref” paragraph no longer applies.
Array[T, N] writes the length down and is laid out inline
(ADR-152 D4). Array[T] leaves it open — beliebig, aber fest:
arbitrary, and fixed for each use. Where that use gets its length is what the
position decides.
In a parameter the call says which. fn total(xs: Array[i64]) takes an
array of any length, and every call knows its own — so the type has a size
there and the function is generic over it. The language below has the same
shape and the same name for it, a const parameter, so the function is written
once and monomorphised per length. Two arrays in one signature are two lengths:
fn zip(a: Array[i64], b: Array[i64]) takes any two and not two of the same.
Under a ref the pointer carries it. ref Array[T] is a view of a run —
Rust’s own &[T] — and needs no length in the type at all, because a view of a
run is a pointer and a count. That is not a second rule: owning needs a size
and viewing does not, which is ADR-282’s own arrangement for
text one type over, where the compiler picks the state per use.
In a field or a result it is NK1182, because there is no call to ask and
the two readings left are both something else. A struct generic over its length
makes two Sections of different lengths two types, which is exactly not
what a parser produces — ADR-179’s own motivating case is a field
whose run differs per value. A result’s length would be bound by nothing. The
message names three ways out, because which was meant is not something this
compiler can know: Vec[T] to own and grow, ref Array[T] to view, and
Array[T, N] to write the length down.
Without that refusal the language below answers, with the size for values
of type [i64] cannot be known at compilation time about a file nobody wrote,
which is the sentence ADR-182 D2 removes one construct over.
& leaves the language, and the bracket form with it.Two spellings for one idea is what this record exists to remove, so & goes
from the grammar and ref [T] goes with it — ref Array[T] is the run’s one
spelling (D3). && stays what it is, a program’s and, and the generated file
keeps Rust’s & throughout: D2’s own line is that the compiler’s word and the
language’s are allowed to differ, and only one of them is the language.
A program written with & gets a way out and not just a verdict. The
grammar’s own found unexpected token & is true and helps nobody, so the
parse error carries a note naming the word and the three shapes it writes
(Part III C.2).
A ledger still reads the old spelling, and that is the one exception: a
.contracts file is a machine format this compiler reads, not a program a
person writes, so &str, &[T] and &mut T all parse back — as the types
their new spellings name. Tolerance there costs nothing and a stale checkout
keeps building.
Display and parse are a matched pair and
.contracts is that format, so the files on disk say ref — which is the
surface a reviewer reads (ADR-290).&, and the emitter writes &str for a
view of String — the one place the compiler’s noun and the language’s
differ.&self should exist at all. ADR-094 D1 already
makes a parameter the body only reads a view without the word, so
fn mean(self) may already say what fn mean(ref self) says. That is a
second language change and it is not this one; here the receiver is spelled
ref self and means exactly what &self meant.Vec[T] is what a program writes and
nothing here changes it.