Browse the docs

silk.mem.shared.

Shared ownership of one mutable value on one thread, with access through callbacks.

When to use#

Use Shared when several values that you own separately, such as stored callbacks or computations that run later, must all use the same mutable state, and a borrow cannot live long enough. For one owner, use the value directly or silk.mem.box.Box.

Details#

Shared.make allocates one time. Shared.clone, Shared.with, and Shared.withMut do not allocate. Each handle counts as one owner. When you drop a handle that is not the last one, the value stays. When you drop the last handle, the value is dropped and the allocation is released. A handle stays on the thread that made it.

Access is exclusive for the duration of the callback, also for Shared.with. A nested access to the same value through any handle traps before the nested callback starts. This applies to all four combinations of with and withMut.

Gotchas#

Handles that refer to each other in a cycle are never dropped, so the value leaks until you break the cycle. There are no weak handles. Do not call code that can access the same value from inside a callback. Get the data you need, return from the callback, and then call that code.

Examples#

Update a value through one handle and read it through another#

silk
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.mem.shared { Shared }

struct Counter {
  value: i32,
}

fn addTwo(counter: &mut Counter) -> i32 {
  counter.value = counter.value + 2
  return counter.value
}

fn read(counter: &Counter) -> i32 {
  return counter.value
}

pub effect fn main() -> i32
  ! OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let first = run Shared<Counter>.make(Counter { value: 40 })
    |> Effect.provideMut<Allocator>(&mut allocator)
  let second = Shared<Counter>.clone(&first)
  let updated = Shared<Counter>.withMut<i32>(&second, addTwo)
  if updated != 42 || Shared<Counter>.with<i32>(&first, read) != 42 {
    return 1
  }
  return 0
}

Import as Shared with import silk.mem.shared { Shared }.

Public declarations: 1.

Shared#

silk
pub struct Shared<T>

A strong handle to one value of type T that other handles can also own.

When to use#

Use it when several values that you own separately, such as stored callbacks or computations that run later, must all use the same mutable state, and a borrow cannot live long enough. For one owner, use the value directly or silk.mem.box.Box.

Details#

Drop is automatic. The value is dropped when the last handle is dropped. A handle cannot move to another thread.

Shared.make allocates one time. Shared.clone, Shared.with, and Shared.withMut do not allocate. Access is exclusive for the duration of the callback, also for Shared.with. A nested access to the same value through any handle traps before the nested callback starts.

Gotchas#

Handles that refer to each other in a cycle are never dropped, so the value leaks until you break the cycle. There are no weak handles.

Implementation Shared<T>#

silk
impl<T> Shared<T>

Associated function make#

silk
pub effect<'env> fn make<'env>(value: T) -> Shared<T> ! OutOfMemoryError ? &mut Allocator

Allocates storage, moves value into it, and returns the first handle.

Errors#

  • OutOfMemoryError if the Allocator cannot supply the storage. No handle is made, and value is dropped.

Details#

The handle does not keep a reference to the allocator after make returns.

Method clone#

silk
pub fn clone(self: &Self) -> Shared<T>

Returns a new handle to the same value. It does not allocate and does not touch the value.

Gotchas#

If the handle count reaches its maximum, clone traps before it changes the count.

Method withMut#

silk
pub fn withMut<A>(self: &Self, use: once fn(&mut T) -> A) -> A

Calls use one time with a mutable borrow of the value and returns the result of use.

Details#

The borrow cannot escape the callback, and it cannot stay live across a suspension.

Gotchas#

If use accesses the same value again through any handle, the program traps before the nested callback starts.

Method with#

silk
pub fn with<A>(self: &Self, use: once fn(&T) -> A) -> A

Calls use one time with a shared borrow of the value and returns the result of use.

Details#

with uses Shared.withMut internally, so the access is exclusive for the duration of the callback. The callback cannot change the value through its &T.

Gotchas#

A nested access to the same value through any handle traps, also when both accesses use with.

Category: Memory.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.

View the source of this page