Views are borrowed: no bare str, slices or cstr, and no view outside a reference's places
Decided: every point below, as proposed (r89, 2026-10-30, by the user). Not yet implemented: T-0109 lists the tasks, in the order r90 set. Refines D-0091 and D-0003; supersedes the value-view parts of D-0039, D-0050 and D-0092.
Settled on the way, 2026-10-30 (r90, by the user): three places where the points below did not fit the rest of the language.
- A type parameter or an associated type may be marked
view(point 8 refined). Point 8 alone refusedT = SliceIter<i32>, which §8.5’s projections rely on:first(&list.iter()),count(xs.iter()), an adapterNumbered<SliceIter<Monster>>. A parameter writtenview T, or an associated type a trait declaresview type Item, may be a view, and the generic body checks a value of it as one: it lives only where a reference does, carries a tie, and passes only to anotherviewparameter. A struct with aviewparameter is aview struct. A plainTis still never a view, so generic bodies stay fully checked.Iterate::Item,Iterable::IterandIterableMut::IterMutareview types. - An optional view is a pointer (point 3’s spelling corrected).
&T?is a reference to an optionalT(§5.6), so a method handing back an element or nothing is-> ^T in self@items, and text or a slice that may be absent is^stror^[]Twhere it wasstr?: tied when a safe call returns it within, soorturns it into a reference safely (point 11).^stris then the text pointer itself, a{ ptr, len }that may be null, no longer a pointer to astrvalue.(&T)?written out is an error that offers^T, and aT::Item?whose instance is a reference is that pointer, which settles T-0085. - A view struct holds references (D-0003 refined). D-0091 kept D-0003; point 3 relaxes it for view structs only, which are placed as a reference is, so a reference still lives only where references live.
Also settled, each in its task: view is a keyword only before struct, type and a type
parameter, so let view = … stays valid (T-0111);
a pointer parameter is untied, so p or return on one needs unsafe, checked in dz_flow
(T-0114); process_env
returns ^str (T-0112). The order is
now T-0113, T-0111, T-0109, T-0110, T-0112, T-0114: view structs come first, since Chars,
Split, Lines and SplitWhitespace hold a str field and SliceIter a slice, which
only a view struct may once views are borrowed.
The question. str, []T and cstr are views that look like values: they can be
stored in fields and containers (List<str>), so a type parameter may be a view and a struct
may hold one. r88 had to leave each such case untied. How do the ties become complete, with
no hole other than what is marked unsafe?
The rule. A view is anything that points into memory something else owns. Every view
has a tie, known where it is made. Views live only where references live — locals,
parameters, results, temporaries — never in a field, a container or a type argument. The one
exception is const &, which points at static memory, needs no tie and may go anywhere.
Anything untied is a raw ^ pointer, and turning a raw pointer into a tied reference is
unsafe.
- Text is
&str, and static textconst &str(r87’sconst str). Barestris no longer a type a value can have. - Slices are
&[]Tand&mut []T, and static tablesconst &[]T(the openconst []Tquestion). Fixed arrays[N]Tstay values. - View structs.
view struct SliceIter<T> { m_slice: &[]T }may hold references and is itself a view: placed as a reference is, with one tie for everything its fields view, and elision andinas for a reference. A method returns through a tie on the field,tie @items = m_sliceand-> ^T in self@items(r90; first written-> &T?, which §5.6 makes a reference to an optional), so what it returns outlives the iterator. The marker is explicit, so a struct never becomes unstorable because a field was added. An optional, tuple or array of views is a view by the same rule, with no marker. cstrtoo.&cstris a tied view (String::as_cstr() -> &cstr in self@text),const &cstra literal, and^cstrC’s pointer, untied. A Cconst char*parameter takes any of the three; a C result is^cstr. A C++std::string_viewparameter is&str, a result^str.const &may be stored:List<const &str>and aconst &strfield are fine. It applies tostr,cstrand[]T.- Spelt
const &str: the constness is the reference’s (what it points at never dies), in r87’s word order.&const strwould say the text cannot change, which every&stralready says. - A
Stringpasses as&strthroughImplicitAs<&str>andImplicitAs<&cstr>: at arguments only, borrowed, tied to theString. No general deref coercion. - No view is a type argument (DZ0517 extended):
List<&str>andT = SliceIter<i32>are errors,List<const &str>is not. ATis then never a view, so generic bodies are fully checked. (r90: except a parameter or associated type markedview, above.) - Function types write
in:fn(a: &T, b: &T) -> &T in (a, b). (Built in r91, T-0113.) - A tagged union’s payload needs no tie syntax: a write that may change the variant
kills every payload (r82), so
in uandkills uare already exact. Closes T-0107’s question. p or returnon an untied^Tisunsafe. A pointer with a known tie, one a safe call returned within, still converts to a tied&Tsafely; one from a field, a cast or C converts only inunsafe. A context struct’s^mut World(§5.2) therefore needsunsafeto use, which is honest: that aliasing is exactly what §6.7 cannot check. Rejected: keeping it safe as the one documented hole.
What stays unchecked, by design and marked: raw pointers and unsafe blocks; std’s
trusted bodies, which T-0116
tests in debug builds; and threads (D-0011, deferred). Every exemption r88 left
goes: a result that is a view only through T (point 8), cstr from nothing and extern
results (point 4), by-value view parameters (point 3), and function types (point 9).
Spec: §5.3, §6.7, §15, §20 are revised as each task lands; r89 records the decision.
