.clone(), and .to_owned() Is the Language Below’sStatus: Superseded by ADR-282 — its D1-D4 are D7 (its .to_string() half in D8), D9, D10 and D8 there
Date: September 25, 2026
Target Version: Nikaia 0.0.192
Answers: the owner’s question does .to_owned() still make sense in the
language, or is it a detail for the compiler? — and the owner’s yes to one
word, .clone()
Refines: ADR-107 D3 (which named .to_owned() as how a
program asks for text of its own, with .to_string() beside it)
Related: ADR-005 §3, ADR-008 D5 (a copy is
written, never inserted — which stays), ADR-215 D4 (the compiler
already writes to_owned below for a clone), ADR-137 D5 (..=
withdrawn naming its replacement — the shape D1 follows)
That a copy is written is the language’s, not the compiler’s: a copy costs as much as the value is large, and one inserted on its own would run on every turn of a loop over a billion rows with nothing in the source to show it (ADR-005 §3, ADR-008). So a program needs a word for it.
It had three, and two sets of advice:
.to_owned(), which Part I and ADR-107 D3 named for text — and
which no ledger entry described, so the checker could not see it and
handed it to rustc unexamined;.clone(), which the ledger described and NK2101, NK2105 and NK2106
proposed;.to_string(), kept by ADR-107 D3 for a reader from another language.NK1105/NK1106 said .to_owned() and NK2105 said .clone() for the same
act. Part I’s own rule for ranges is one spelling per meaning.
The reason the language below has two words is its own: .clone() of a
reference copies the reference, so &str and &[T] need .to_owned() to
become a String and a Vec. This language has no reference to copy — a copy
of text is text of its own, whatever it was copied from — and since
ADR-215 D4 the compiler writes to_owned below for a clone that
needs it. The distinction had become the compiler’s.
.clone() is the copy; .to_owned() is NK1189.One word, for text and for everything else. .to_owned() is refused naming
.clone(), as ..= was refused naming ... A program’s own method called
to_owned is not touched.
.to_string() stays, and not as a third name for a copy: it is the text
form of a value, for every type — a number formatted, text as it is. (Until
0.0.193 that was a copy for text; D4 made it the text itself.) Refused on text alone, one expression would be
right or wrong by its receiver’s type, x.to_string() in a body generic over
x among them. (The first draft of this record refused it on text; 81 test
programs wrote "…".to_string(), and reading why settled it.)
A clone that goes to a std entry is to_owned below (ADR-215 D4), and so
is a clone of a slice — a ref Array[T], read or declared — which hands
back a Vec[T]. The analyses that read a copy by name to know that a value
owns a buffer (contracts::keep, contracts::tether) read clone of text
as to_owned was read: a literal, or a name whose type was written as text. A
clone of anything else keeps pointing where the original’s views pointed,
which is right for a list of views and the direction that keeps more otherwise.
.clone().NK1105, NK1106, NK1183, NK2302, NK2304 and the tether’s refusals, Part
I and Part III, the README and the examples’ README.
The owner’s question: why must to_string be a copy — it could be a
reference. It could, and it should. .to_string() on text answers the
receiver’s own type: a view stays a view, a literal stays a literal, owned text
stays the same owned text (a name of it is handed over, as let b = a is).
Below, the call is not written. Only .clone() copies, so a copy is still
written exactly once where it happens.
And the owner’s follow-up: "nobody".to_string() should not have to be
written if to_string does nothing — "nobody" is enough. It is: a literal is
built into text of its own wherever it is kept (ADR-207 D2), and
0.0.193 closes the places that still needed the call — a tuple’s parts
(return (1, "one") for an (i64, String)) and a ?? inside an f-string
hole, where a literal’s position was keyed by its offset into the hole and
collided with another hole’s (now keyed by statement, hole and offset, in the
checker and the emitter alike). A view put where text of its own is kept is
refused with .clone() named, .to_string() or not.
The keep and tether analyses follow: to_string of a literal makes no buffer;
of a name written with a non-text type (seed.to_string(), seed: i64) it
makes one; of anything else the walk cannot tell, and it says unsure, which no
refusal stands on. A let whose written type is String holds text of its
frame’s own.
Left: .to_string() on text is now redundant and is not refused or hinted —
whether it should be is the owner’s to decide.
All of it, in 0.0.192: NK1189, the slice copy, the copy of text read as a
buffer, the help texts, the documentation, the test programs in this
repository rewritten from .to_owned() to .clone() (none of the examples
wrote it; examples/http’s one .to_string() of text became .clone() for
the sake of the example, not because it was refused), and tests in
crates/nikaia/tests/handed_over.rs.
D4 in 0.0.193: text_as_is from the checker to the emitter, the tuple
literal, the hole-keyed literal positions, the buffer rules, and the test
programs, examples and Part I rewritten from "…".to_string() to the bare
literal (or let x: String = "…" where a test needs owned text in a name).