?? Beside a Jump Is a View Wherever It StandsStatus: Superseded by ADR-279 — its D1-D2 are D10-D11 there
Date: October 3, 2026
Answers: what let s = c.signature ?? return false means where c is
only borrowed - refused as a part of a loan taken (NK2106), or a view of
the field. Met moving contracts::keeps’ lending rule into Nikaia (#125),
where the program had to go round it; the owner chose option B.
Related: ADR-259 D1 (?? lends its left side where the
answer is read and takes it where it is kept), D3 (a fallback is lent only
where a view of it lives as long as the answer); ADR-214 D2
(NK2106: a part of something lent handed to what keeps it);
ADR-138 D1 (a fallback that jumps); ADR-213 and
#297 (let found = m[k] binds a view of what the map keeps);
ADR-250 D3 (a compiler’s gap is closed in the compiler, not
gone round in the program)
fn lends_in(contract: ref FnContract, at: i64) -> bool {
let signature = contract.signature ?? return false
…
}
ADR-259 D1 makes a let a position that keeps the answer, so the left
side of ?? is taken. Here the left side is a field of contract, which is
only borrowed: nothing can take a part of it, and the program was refused
with NK2106. What does a let of a borrowed left side beside a jump
mean?
ADR-259 was written for names the function owns, where taking is possible.
It does not say what happens where the left side is itself only lent. Without
an answer, a program wrote contract.signature?.clone() ?? return false and
paid a copy, or went round through a helper function whose parameter is a
ref Signature?.
| Language / tool | Its answer | What it costs there | Source |
|---|---|---|---|
| Rust | let Some(s) = &c.signature else { return false }; binds &Sig; matching on a place behind a reference binds by reference (“default binding modes”) |
nothing; the reference is checked by the borrow checker | the reference’s let-else and match ergonomics, from memory |
| Swift | guard let s = c.signature else { return false } binds a copy of the value (copy-on-write for large storage) |
a copy where the optimiser cannot avoid it | from memory, not checked |
| Kotlin | val s = c.signature ?: return false binds the same reference |
none; objects are references | from memory, not checked |
| C# | if (c.Signature is not { } s) return false; binds the reference for a class, a copy for a struct |
a copy for a struct | from memory, not checked |
What transfers. The languages that have borrowing as a rule (Rust) bind a reference where the matched place is behind one, which is the case here. The ones without it bind the same reference (Kotlin, C# classes) or copy (Swift, C# structs). None refuses the program.
let signature = contract.signature?.clone() ?? return false // a copy
let signature = contract.signature ?? return false // `ref Signature`
| D1 the special case pays, not the common one | D2 the compiler works, not the developer | D3 no cost for the common case | D4 consistent with itself | If it is wrong | |
|---|---|---|---|---|---|
| A | every such line pays a copy or a helper | the developer writes the copy or the helper | a copy of the field | consistent with ADR-259 D1 read literally, but refuses the one meaning the line can have | nothing breaks; programs keep going round it |
| B | only a program that keeps the view past the loan writes .clone() |
nothing to write | no copy | the same as let found = m[k] (#297) and ADR-259 D3, whose test - a view of the answer lives as long as the answer - a jump meets, having no value |
a binding that was refused now compiles; undoing it refuses it again |
B. It is the only meaning the line can have, and it is not a new rule: ADR-259 D3 lends where the fallback leaves the answer a view, and a jump leaves nothing else.
Where the left side of ?? is a name or a field rooted in something only
lent - a ref parameter, a for over a place, a let over one - and the
fallback is a return, throw, continue or break, the answer is a view
of the left side, in a reading position and in a let alike. The option is
opened, not taken: .as_ref() below, .as_deref() for text. A left side the
function owns keeps ADR-259 D1 unchanged.
Returned, stored or handed to what keeps it, the view meets the refusals every
view meets, with .clone() as the copy.
Why not A. It refuses a line whose only meaning is a view, and the way round it - a copy, or a helper whose parameter is the view - is exactly what ADR-250 D3 says a program should not have to write.
let s = c.signature ?? return false and let label = c.label ?? continue
over a lent c compile and bind views; nothing is copied.ref T?
parameter can write the line directly; tools/lends.nika does.