?. Reaches Through a View, and the Receiver Stays UsableStatus: Superseded by ADR-278 — its D1-D4 are D16, D17, D18 and D23 there
Date: September 16, 2026
Target Version: Nikaia 0.0.8
Related: ADR-052 D6 and D8 (?. over a field, and what it
took), ADR-066 D3 (?. over a method, and its match),
ADR-094 D4 (a let over a place is a view of it),
ADR-107 D1 and D3 (a value’s state is the compiler’s per use;
a copy is written or refused, never inserted), ADR-008 (a view
and the buffer that owns it), Part I 3.5 and 6.6
let name = user?.name followed by println(user) was refused in the
language below with use of moved value, and the specification called that
a rule: ?. takes the value it reaches through. The rule came from the
lowering — Option::map takes its receiver by value — and the record that
named it translated rustc’s note and dropped the three hints that named
.as_ref() and .clone(), because the language has neither.
That is the shape docs/language-review.md §1.1
found under the & at every call: a Stage-0 choice became a sentence in Part
I, and the message was translated instead of the cause. In every language
that has ?. the operator reads through its receiver and leaves it where it
was. And since ADR-094 D4 and ADR-107 this
language has the rule that decides such a case for everything else: whether a
value is a view or owned is the compiler’s, per use, and a copy is something a
program writes.
?. takes nothing. It reaches through a view of its receiver.user?.name reads user where it lies. user is usable on the next line,
in a println, in a second ?., in a call. There is no move and no message
about one.
T? whose state is the compiler’s, as everywhere.Where the reached member copies — a number, a bool, a char — the result
is a copy. Where it does not, the result is a view tethered to the
receiver, kept alive by the rules Part I 6.6 and ADR-008
already apply to any view of a place. A program that wants to keep the result
past its receiver writes .to_owned(), which is ADR-107 D3’s
rule for text applied to what ?. reaches. Nothing is copied that the
program did not write.
as_ref() before the map, a borrowed scrutinee before the match.x?.a is x.as_ref().map(|it| &it.a) — with the copy where D2 says copy —
and ADR-066 D3’s match for a method takes x.as_ref() as its
scrutinee. The flattening of ADR-052 D6 (map against
and_then) is unchanged; it only reads through a reference now.
ADR-052 D8’s translation of “Option::<T>::map takes
ownership of the receiver” goes with the move it explained. A receiver used
again after a ?. is an ordinary program, and the checker says nothing.
let name = user?.name; println(user) compiles. The one C.1 violation Part
I had written down as a rule is gone.?. behaves as a field read does: a copy or a view. A
program that stored it past the receiver’s scope already had to write what
it wanted; now the compiler tells it so in this language’s words where it
forgot, by the tether rules and not by rustc.?., counts.get(fragment)?.n ?? 0 in
examples/k-nucleotide/src/main.nika, reaches a copy through a temporary.as_ref() in two lowerings, the tether analysis reading
a ?. as a view of its receiver, and the removal of one translation.?. on the left of an assignment (user?.name = …), which the language
does not have and this record does not add.?. whose receiver is itself a view of a view; the tether rules answer
it as they answer any nesting.Nothing. x?.a lowers to x.map(|it| it.a), a method reach to a match
over x by value, and a receiver used again is refused below with the
translated note. The order of work:
as_ref(), with the copy where the member copies;?. as a view of the receiver
where it is one;crates/nikaia/tests/.#192 carries it.