mut self for ref mut self, self a view unless keptOpen and answer this issue on GitHub.
ready · opened 2026-10-27 · updated 2026-11-03 · 1 comment
Does a method’s receiver follow the rule every other parameter follows (Part I 6.5)?
For a parameter, ref is no longer written:
fn fill(mut out: Vec[i64]) and passed as ref mut. Nothing shows at the call.ref is only an assertion. At a call it is refused (NK1137).The receiver is the one exception:
| Today | Meaning | Uses in tools/*.nika (all .nika) |
In Part I-III |
|---|---|---|---|
ref self |
view | 761 (873) | 13 |
ref mut self |
change in place | 471 (519) | 11 |
self |
by value: the call moves the receiver | 76 (78) | - |
mut self |
parse error (“Expected :”) |
0 | 0 |
Probe on today’s develop: a fn show(self) -> i64 { return self.n } called twice on c is refused with “Use of moved value: c. C::show takes ownership of the receiver self”, although the body only reads a copied field. A plain parameter in the same place would be a view.
The deleted converter wrote the parameter rule where a method became a free function. Its R83 said ref mut self -> mut state: CheckState and ref self -> state: ref CheckState. So the same thing has two spellings, depending on whether it is a receiver or not (ADR-140).
A: nothing changes. The receiver keeps its three written forms.
B: mut self replaces ref mut self. mut self changes the receiver in place and is passed as ref mut, as mut out: T is. ref self and self (by value) stay as they are.
C: B, and plain self follows the parameter rule. self is a view unless the body keeps it: hands it back, moves it into a field, gives it to a task, or passes it on to something that keeps it. Then:
fn show(self) -> i64 { return self.n } is a view, and c.show() twice is fine.fn close(self) (which consumes the resource) and a builder fn get(self, …) -> Server stay by value, because their bodies keep self.ref self becomes an assertion, as ref on a parameter is.impl Counter {
fn value(self) -> i64 { return self.n } // view (C); today: moves
fn hit(mut self, by: i64) { self.n = self.n + by } // today: ref mut self
fn into_parts(self) -> (i64, String) { return (self.n, self.name) } // keeps self: by value
}
| Option | D1 the special case pays | D2 compiler works | D3 no cost in the common case | D4 consistent | If it is wrong |
|---|---|---|---|---|---|
| A | no: every method writes ref that no parameter writes |
no | no: 1232 ref words in the tools |
no: receiver ≠ parameter, R83 shows the two spellings | noise; a reading method written self moves its receiver |
| B | partly | partly | half: ref self stays |
half | small |
| C | yes | yes: the walk that decides a parameter’s view decides the receiver’s | yes | yes: one rule for every parameter, self included |
a body change turns a view into a move. The ledger shows this already, as it does for every parameter |
Recommendation: C, built in two steps so that each one stands alone. B is C’s first step.
What speaks against C, and why it does not outweigh it:
mut self for “owned, mutable”. Nikaia’s own mut out: T already means “changed in place”, and mut self reads the same way.nikaia fmt rewrite does the work.A
mutparameter handed to anothermutparameter is passed straight on.ref selfis written by the author, and that shape isNK1131, as is amutparameter given away whole: …
The middle sentence makes no sense. Read against NK1131 in Part III (“a mut parameter whose type is a view, handed back”), it probably meant: A mut parameter whose type is a view and that is handed back is NK1131, as is a mut parameter given away whole. This is fixed in whichever option is chosen (a text fix, no version raise of its own).
fn hit, fn drop, fn cleanup, fn record, fn note). It also fixes the garbled sentence. ADR-382 D5 says mut self there.mut self as ref mut self, and keep ref mut self working during the transition. Tests in tests/compiler/: mut self changes in place; mut self given away whole is NK1131.ref mut self -> mut self in tools/*.nika, packages/, examples/, guide/. Then ref mut self is refused with a help that writes mut self.self is a view unless the body keeps it. Decide it with the walk that decides a parameter, and write it to the ledger. Tests: show(self) twice is fine; close(self) and into_parts(self) still move.ref self -> self in the same places. ref self stays an accepted assertion (the same as ref on a parameter), or is refused. Which of the two is part of this decision; I recommend accepting it as an assertion, for symmetry with parameters.Generated by Claude Code
Decided by the owner (2026-10-27): option C, but not now. Other work comes first, so the order of work (docs/priorities.md) decides when this is built. Nobody starts the To build list before the score puts it next.
Still open, to be settled at step 5: whether a written ref self stays accepted as an assertion (the recommendation) or is refused.
Generated by Claude Code