Issue #1213: Parameters say keep, ref leaves the language, a result’s source is inferred or written from (ADR-views-3)

Open and answer this issue on GitHub.

ready · opened 2026-11-03 · updated 2026-11-03 · 0 comments

Decided by the owner (2026-11-03): option B of the former #1211 with the word keep, and option D below for a result’s source. This issue now carries the whole topic; #1211 (the keep question), #1115, #1093, #1152, #1165 and #1171 are folded into it. The record is ADR-views-3 (pushed); the changed rules of ADR-094, 184, 202, 251, 353, 354 and 358 carry its notes.

What holds

  1. A parameter that keeps its argument says keep. Keeping means storing it in a field, returning it, or handing it to a task. A plain parameter is lent: the caller’s value is usable again after the call. The body is checked against the signature: a body that keeps an unmarked parameter is refused, with a help that adds keep; a keep that is never kept gets a warning. Methods and trait methods say it too. self follows the same rule: self looks, mut self changes in place, keep self consumes the object.
  2. ref leaves the language, except in extern "C", where it keeps its C meaning. ref self becomes self, ref mut self becomes mut self, and return ref s becomes return s.
  3. Fields, element types and local bindings are inferred. A field or element holds a tethered view when it is built from a piece of a buffer, and an own value otherwise (the ledger lists such fields, tethered = [...]). A field or element that is changed must be an own value; the error says where to write .clone(). A let from a place only looks; taking the value out is written (remove, drain, .clone()). A struct literal takes a local or a parameter the way a call argument does (the case of #1152).
  4. A result’s source (option D). By default it is inferred: the ledger records it (views), and a caller that changes the source while it still uses the result is refused, with an error naming the function and the parameter. It may also be written on the result: -> String from s, or from a | b for several sources. Where it is written, the body is checked against it. It must be written where there is no body to infer it from: trait methods, function types, and foreign or Rust functions. Elsewhere, for example on public library functions, writing it is optional.

To build

  1. Specification: ADR-views-3 in Part I ch. 6 and Part III text. Remove ref and ref mut from every rule outside extern "C", including the fold step in Part II 10.x, which becomes fn(mut A, T) / fn(mut A, A) (the contradiction of #1093) and the same wording in ADR-372 D9 and 10.7. Then, as one change with every citation moved: move ADR-202, 353 and 354 to docs/history/adr/ (ADR-decision-records-1 D3), since views-3 restates all of them that still holds; rewrite ADR-094 D2 and D6, ADR-184 D1, ADR-251 D4 and ADR-358 D3 in place under their Changed by notes (ADR-094 and 184 keep other live rules).
  2. Checker, keep: a body that keeps an unmarked parameter is refused, and a keep that is never kept gets a warning; this covers self / mut self / keep self and trait methods.
  3. Checker, inferred views: a changed field or element must be an own value (a .clone() help). A struct literal lends a local or a parameter as a call argument does: the struct may not outlive it, and it is no keep while it stays in the function (#1152’s probe).
  4. Checker, result source: from s / from a | b is parsed and checked against the body. It is required on trait methods, function types and foreign functions. A caller that changes a source while using the result is refused, naming the function and the parameter.
  5. Ledger: keeps and views stay. A change of either on a pub function is reported as a contract change, and a written from is recorded as written.
  6. Migration tool (tools/*.nika, a nikaia subcommand): writes keep from the ledger, removes ref everywhere outside extern "C", and rewrites the self forms. Run it over crates/nikaia-std, the packages, the examples, guide/ and the tests, then update the expected outputs. This settles #1115 (ref before a tuple), #1165 and #1171 (NK1261, the “ref is redundant” warning, which then retires).
  7. Tests in tests/compiler/, one per rule above, plus a refusal for each error.

Back to Open Issues