Consume-types in Nova
User-facing guide to working with consume-types: bindings, ownership transfer, view-borrow, lifecycle.
TL;DR
consume x = Token.new(7) // ✓ ownership binding
ro y = x // ✗ E_VIEW_BINDING_FORBIDDEN
consume y = x // ✓ move (x dead, y owns)
ro v = x.release() // ✓ consume via method
- Ownership moves via
consume X = …. - Alias binding is forbidden inside a function body (
let Y = X). - View-borrow is allowed ONLY as a function parameter.
- Every consume-binding must be consumed before scope exit.
What is a consume-type?
A consume-type is a type whose values represent ownership of a non-shareable resource — file handle, mutex guard, builder buffer, network socket. Values cannot be copied, aliased, or implicitly dropped; the owner must explicitly consume them.
Declaration:
type Token consume {
val int
}
The consume keyword on the type declaration marks all instances as
consume-obligated.
Binding rules (D180)
Rule 1 — consume X = … required for consume-RHS
ro t = Token.new(7) // ✗ E_CONSUME_KEYWORD_MISSING
consume t = Token.new(7) // ✓
The compiler statically detects when a binding receives a consume-type
value and requires the consume keyword.
Rule 2 — let Y = consume_var forbidden in function body
consume sb = StringBuilder.new()
ro view = sb // ✗ E_VIEW_BINDING_FORBIDDEN
Aliasing a consume-obligation would create a dangling reference once
sb is consumed; aliasing inside function bodies is forbidden.
Rule 3 — consume Y = X moves ownership
consume a = Token.new(11)
consume b = a // move — a dead, b owns
ro v = b.release() // ✓
After the move, a is consumed; using it triggers a
use-after-consume diagnostic.
Rule 4 — view-borrow via function parameters only
fn snapshot(t Token) -> int => t.val
consume t = Token.new(7)
ro s = snapshot(t) // ✓ view-borrow (bounded by call)
ro v = t.release() // ✓ caller still owns; consume here
Function parameters of consume-type without the consume keyword
are views — bounded by the callee’s scope, never escape.
Consume operations
A consume-obligation is satisfied by any of:
consume X = X_old— move to new binding (Rule 3).X.method(...)where method is aconsume @method.return X— return from function.- Implicit return — trailing expression of function body is
X(or a fluent-chain rooted atX; see [M-73.1-fluent-return- implicit-consume]). - Pass to consume-parameter —
f(X)whereftakesconsume X.
Fluent-return chains (-> @)
A method declared with -> @ return type returns the receiver itself
(Plan 77, D132). Fluent chains compose mutators:
consume sb = StringBuilder.new()
ro s = sb.append("a").append("b").as_str() // chain + consume
When such a chain is the trailing expression of a function body, the chain root’s consume-obligation is satisfied by the implicit return (M3, Plan 73.1 V3).
Diagnostics
| Code | Trigger |
|---|---|
E_CONSUME_KEYWORD_MISSING | let X = ctor() when ctor returns consume |
E_VIEW_BINDING_FORBIDDEN | let Y = consume_var in function body |
W_CONSUME_KEYWORD_UNNECESSARY | consume X = … when RHS is non-consume |
D133-not-consumed | scope-exit with unsatisfied obligation |
D133-use-after-consume | use of consumed binding |
All diagnostics carry machine-applicable suggestions (Plan 50 D102).