Ownership and sending

Ownership tracks values that must have one responsible owner. Most Hew data behaves like ordinary data: reusing it can create an independent logical value. Resources, stream halves, tasks, generators, some closures, and aggregates containing them transfer instead.

type Reading {
    label: string;
    samples: Vec<i64>;
}

fn main() {
    let original = Reading { label: "cpu", samples: [70, 80] };
    var revised = original;
    revised.samples.push(90);
    println(original.samples.len());
    println(revised.samples.len());
}

original and revised are independent values. An implementation may share immutable storage internally, but mutation preserves this observable value behavior.

Bindings are not ownership modes

let makes a binding immutable. var permits reassignment, field or element assignment, and calls to var self methods. Both bindings can hold ordinary data or an affine owner. The value's type and the operation decide whether a second use copies, borrows, or transfers it.

An ordinary function parameter borrows or copies according to its type. consume value: T says the callee needs an owned value. consume self ends ownership of a method receiver. For ordinary copyable data the caller may still keep an independent value; an affine owner moves and cannot be reused from its previous place.

Value and owner categories

CategoryExamplesReuse and cleanup
Ordinary datanumbers, strings, bytes, records, enums, collectionsIndependent value behavior; recursive automatic cleanup
Actor referencea named actor type or actor(M) -> RCopies the actor identity; stop requests termination
Affine resourcefiles, sockets, stream halves, #[resource] valuesTransfers ownership; scope exit closes a live owner
Linear value#[linear] declarationsTransfers ownership; every path must explicitly consume it
Task or generatorTask<T>, generator handlesTransfers ownership; the enclosing construct settles cleanup
Callableclosures and function valuesCopies or transfers according to captured owners and callable capabilities

Aggregates inherit their members' obligations. A record containing a stream half is affine; a collection of linear values must eventually move each element to a consuming operation.

Sending values to actors

Send means that a value can cross an actor boundary without exposing shared mutable state. The compiler derives this property; user code does not implement a Send trait or add a #[send] marker.

Primitive values, strings, actor references, and records, enums, tuples, options, results, arrays, and collections whose members are Send can cross the boundary. Ordinary data arrives as an independent logical snapshot. An admitted affine owner transfers to the receiver. Raw foreign pointers, task and generator handles, and values whose safety cannot be established are rejected.

type Job { id: i64; note: string; }

actor Worker {
    receive fn run(job: Job) -> i64 { job.id }
}

fn main() {
    let worker = spawn Worker;
    let job = Job { id: 42, note: "index" };
    println(worker.run(job).expect("worker completes the job"));
    println(job.note);
    stop(worker);
    stopped(worker);
}

The caller can still use job because ordinary message data is snapshotted. Sending an affine resource instead transfers its sole owner. The same Send check applies to actor call parameters, mailbox submissions, replies, and values captured by a lambda actor.

Loans and collection access

Reading from a collection may temporarily lend an element rather than copy it when the element has no copy operation. While that loan is live, the collection cannot be mutated or transferred. Hew infers these loans; source code has no lifetime annotations.

Use resources for deterministic cleanup, actors for delivery and isolation, and functions for receiver and callable ownership contracts. For a more gradual introduction, read the ownership concepts guide.