Ownership handles
API summary (generated from the Beans source by npm run coverage): 8 types · 21 instance methods.
An ownership handle is a builtin type that owns a value and controls how you reach it. Different handles give different rules: one owner, shared owners, locked access, or a value sent between threads. This page lists each handle and its methods. For the full ownership model, read the memory model. For threads and channels in context, see concurrency.
Box, Arena, Shared, and Mutex are move-only outer handles, like List and
Map. When you bind, assign, or return one, use move. Function parameters borrow
by default.
Box<T>
Section titled “Box<T>”Box<T> owns one value on the heap. It is a move-only handle.
new Box(value)Box<T>.get() -> TBox<T>.set(T)new Box(value)allocates one heap slot and takes ownership ofvalue.get()returns a copy of the value;set(value)replaces it.
let b: Box<int> = new Box(10)b.set(20)let n: int = b.get()Arena<T>
Section titled “Arena<T>”Arena<T> holds many values and hands back a stable integer handle for each. It is
move-only.
new Arena(capacity)Arena<T>.add(T) -> intArena<T>.at(int) -> TArena<T>.get(int) -> Option<T>Arena<T>.len() -> intArena<T>.clear()new Arena(capacity)starts with room forcapacityitems.add(value)storesvalueand returns its handle.at(handle)reads by handle and panics if the handle is bad;get(handle)reads by handle and returnsnoneinstead of panicking.len()is the number of items;clear()removes them all.
Shared<T>
Section titled “Shared<T>”Shared<T> gives thread-safe shared ownership. Many owners can hold the same
value; the value lives until the last owner is gone. Copying the handle adds an
owner.
new Shared(value)Shared<T>.get() -> TShared<T>.downgrade() -> Weak<T>get()returns a copy of the value.downgrade()makes aWeak<T>that does not keep the value alive.
Shared<T> is Send and Sync only when T is both.
Weak<T>
Section titled “Weak<T>”Weak<T> points at a Shared<T> value without keeping it alive. Use it to break
reference cycles.
Weak<T>.upgrade() -> Option<Shared<T>>Weak<T>.is_expired() -> boolupgrade()returns a real owner again, ornoneif the value is already gone.is_expired()is true once the value is gone.
let s: Shared<int> = new Shared(1)let w: Weak<int> = s.downgrade()match w.upgrade() { some(owner) => io.println("{owner.get()}"), none => io.println("gone"),}Mutex<T>
Section titled “Mutex<T>”Mutex<T> guards a value so only one thread touches it at a time. It is move-only.
new Mutex(value)Mutex<T>.with_lock(fn(T) -> unit)with_locktakes the lock, runs your function on the value, then releases the lock. The lock is held only for the length of the call.
let m: Mutex<int> = new Mutex(0)m.with_lock(fn(v: int) -> unit { io.println("locked value is {v}")})Channel<T>
Section titled “Channel<T>”Channel<T> sends values between threads. It holds up to capacity items.
new Channel(capacity)Channel<T>.send(T)Channel<T>.receive() -> Option<T>Channel<T>.close()send(x)puts a value in.receive()takes a value out; it returnsnoneonce the channel is closed and empty.close()says no more values will be sent.
Thread<T>
Section titled “Thread<T>”Thread<T> is a running thread. You do not make one with new; you get it from
thread.spawn (see concurrency and the
standard library).
Thread<T>.join() -> Tjoin()waits for the thread to finish and returns its result.
AtomicInt
Section titled “AtomicInt”AtomicInt is a single integer that many threads can update safely. Its
operations are sequentially consistent.
new AtomicInt(0)AtomicInt.load() -> intAtomicInt.store(int)AtomicInt.add_and_get(int) -> intnew AtomicInt(0)starts the counter at a value.load()reads it;store(v)writes it.add_and_get(v)addsvand returns the new value.
let count: AtomicInt = new AtomicInt(0)let now: int = count.add_and_get(1)Handles working together
Section titled “Handles working together”A counter guarded across two threads, joined with Thread.join:
import std.ioimport std.thread
fn main() { let counter: AtomicInt = new AtomicInt(0)
let a: Thread<int> = thread.spawn(fn() -> int { var i: int = 0 for i < 1000 { counter.add_and_get(1) i += 1 } return 0 }) let b: Thread<int> = thread.spawn(fn() -> int { var i: int = 0 for i < 1000 { counter.add_and_get(1) i += 1 } return 0 }) a.join() b.join()
io.println("counted {counter.load()}")}See also
Section titled “See also”- The memory model, ownership, move, and borrowing.
- Concurrency, threads, channels, and locks in use.
- Atomics,
Atomic<T>andMemoryOrder.