ADR-184: A View Is Spelled ref X, and Text Has One Noun

Status: 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)


1. Context

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.

2. Decisions

D1 — 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.

D2 — Text has one noun, and 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.

D3 — 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.

D4 — & 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.

3. Consequences

4. What this does not decide

This site is open source. Improve this page.