Move Semantics¶
Overview¶
Move semantics transfer ownership of handle values between expressions and variables. Handles are unique values, and move marks an explicit ownership transfer.
Syntax¶
Rules¶
Move Syntax¶
The move keyword MUST only be applied to lvalues. The moved expression MUST have a type that transitively contains an owned handle.
Move Source Invalidation¶
After moving a handle, the source lvalue MUST be invalidated. For struct handles, the source MUST be set to null. For slice handles, the source MUST be set to a zero-length empty slice.
Handle Uniqueness¶
Assignment from a handle MUST use move to explicitly transfer ownership.
Handle-Bearing Rvalue¶
A handle-bearing rvalue is an rvalue whose type transitively contains an owned handle.
Handle-Bearing Lvalue¶
A handle-bearing lvalue is an lvalue whose type transitively contains an owned handle.
Handle Movement from Struct Members¶
Moving a handle from a struct member MUST require a write capability on the enclosing struct. Attempting to move a handle member through a read capability MUST be a compile-time error. Assigning a handle member to a variable through a read capability (e.g., let h = r.inner) MUST be a compile-time error, as assignment from a handle requires move which is prohibited through read. Moving a handle from a struct member MUST invalidate that member. For struct handle members, the member MUST be set to null. For slice handle members, the member MUST be set to a zero-length empty slice.
Moving Handles from This¶
Inside a member function body, a handle member MAY be moved via move this.handleMember if this has type write StructType. Moving a handle member via this MUST invalidate that member. Attempting to move a handle member when this has type read StructType MUST be a compile-time error.
Capability Restriction¶
A handle MUST NOT be moved while any live capability derived from that handle exists. A capability value is live from the point at which it is produced (via the read or write operator) until the end of the scope in which that capability value is stored. If a capability is copied, each copy is independently live for the remainder of its own storage scope. Temporary capability values that are not bound to a variable are live for the remainder of the full expression in which they are produced. The compiler MUST enforce this constraint at compile time.
Nested Scope Semantics¶
Moving a handle in a nested lexical scope MUST be permitted without an explicit transfer statement. Scope nesting by itself MUST NOT prevent move; correctness MUST be enforced by move validity, capability rules, and region lifetime rules.
Control-Flow Join Invalidation¶
If a handle-bearing lvalue MAY be moved on any path through an if statement, that lvalue MUST be treated as moved after the merge point. For while loops, the compiler MUST NOT treat a handle-bearing lvalue as moved after the loop unless the lvalue is moved on every path that reaches the loop exit, including the zero-iteration path.
Deprecated with Block Compatibility¶
The with names { ... } form MAY be accepted as compatibility syntax, where names is one identifier or a comma-separated list of identifiers. In this form, with MUST have no semantic effect. Names listed after with MUST be ignored and MUST NOT require name resolution or type validation.