No matching definitions.

tur/forms/references

stdlib/forms/references.tur

ref<T>, lref<T>, rc<T> and weak<T>, the builtin reference forms.

The compiler implements these itself (src/compiler/elab_memory.c), so there is nothing to import. This file is reference only: it declares nothing the compiler reads.

  • ref<T> is a single-owner heap cell. A ref bound by let is freed when its scope exits (or earlier, by drop!), and is unique: binding or passing it moves it, and a second use is TUR-E0201.
  • lref<T> is the linear version: it must be consumed exactly once.
  • rc<T> is a shared, reference-counted cell. rc/clone adds an owner and rc/drop releases one; an rc bound by let is released at scope exit. Field access reads through it: (.x r) on an rc<Point>.
  • weak<T> observes an rc<T> without owning it -- the way to break an rc cycle.

For weak<T>, use tur/weak (rc/downgrade, weak/upgrade, weak/alive?, weak/drop); the builtin upgrade was retired for weak/upgrade. When to use which: ownership-guide.

builtin

ref

(ref [x :T] :ref<T>)

allocate a single-owner heap cell holding a value.

The cell is freed when the binding's scope exits, unless drop! frees it first or it is moved into an rc by rc/from-ref.

xthe initial value

A ref<T> owning a fresh cell.

(let [r (ref 42)] (deref r))  ; => 42
builtin

deref

(deref [r :ref<T>] :T)

read the value a reference points at.

Accepts ref<T>, lref<T>, rc<T>, &T, &mut T and ptr<T>. @x is the same read. Reading a ref or rc does not consume it; reading an lref does -- that is how an lref is used up.

rthe reference to read through

The value it points at.

(let [r (ref 1.5)] (deref r))  ; => 1.5
(let [r (rc/of 7)] @r)         ; => 7
builtin

drop!

(drop! [r :ref<T>] :nil)

free a ref<T> now.

Releases the cell before its scope ends; the scope-exit free is then skipped. Only ref<T> -- an rc is released with rc/drop.

rthe reference to free (consumed)
(let [r (ref 7)] (let [v (deref r)] (drop! r) v))  ; => 7
builtin

ref?

(ref? [x :T] :bool)

is a value a ref<T>?

Answered from the argument's static type, on both engines: true for a ref<T> (an lref<T> is not one), false for anything else. The argument is evaluated, and a ref passed to it is read, not moved.

xany value

true iff x is a ref<T>.

(let [r (ref 7)] (ref? r))  ; => true
(ref? 7)                    ; => false
builtin linear

lref/new

(lref/new [x :T] :lref<T>)

allocate a linear heap cell holding a value.

The lref<T> must be consumed exactly once -- by deref, by moving it into a struct field or a call -- or the program does not compile. A deref of an lref it owns frees the cell once the value is read.

xthe initial value

An lref<T> owning a fresh cell.

(let [p (lref/new 99)] (deref p))  ; => 99
builtin

rc/of

(rc/of [x :T] :rc<T>)

allocate a reference-counted cell holding a value.

The new rc has a strong count of 1. A linear or unique value cannot be shared, so wrapping one is an error (TUR-E0103, TUR-E0202).

xthe value to share

An rc<T> with strong count 1.

(let [r (rc/of 42)] (deref r))  ; => 42
builtin

rc/clone

(rc/clone [r :rc<T>] :rc<T>)

add an owner to an rc.

Increments the strong count and returns a second handle to the same cell. Each handle is released on its own.

rthe rc to share (not consumed)

Another rc<T> to the same cell.

(let [r (rc/of 42) s (rc/clone r)] (rc/strong-count r))  ; => 2
builtin

rc/drop

(rc/drop [r :rc<T>] :nil)

release one owner of an rc.

Decrements the strong count; the value is freed when it reaches 0. The handle is not released again at scope exit.

rthe handle to release (consumed)
(let [r (rc/of 42) s (rc/clone r)] (rc/drop s) (rc/strong-count r))  ; => 1
builtin

rc/strong-count

(rc/strong-count [r :rc<T>] :int)

how many owners an rc has.

For assertions and debugging; a weak observer is not counted.

rthe rc to inspect

The strong count.

(let [r (rc/of 42)] (rc/strong-count r))  ; => 1
builtin

rc->ptr

(rc->ptr [r :rc<T>] :ptr<void>)

borrow a raw pointer to an rc's value.

The pointer is valid while the rc lives. Reading through it needs the unsafe builtins (tur/forms/unsafe).

rthe rc

A ptr<void> to the value.

(let [r (rc/of 5)] (unsafe (ptr-deref (rc->ptr r))))  ; => 5
builtin

rc/from-ref

(rc/from-ref [r :ref<T>] :rc<T>)

turn a single-owner ref into a shared rc.

Moves the cell's value into a new rc with strong count 1; the ref is consumed.

rthe ref to convert (consumed)

An rc<T> holding the value.

(let [r (rc/from-ref (ref 9))] (deref r))  ; => 9
builtin

ref/from-rc

(ref/from-rc [r :rc<T>] :ref<T>)

turn an rc back into a single-owner ref.

The rc must be unique: a strong count of 1 and no weak observers, checked at run time -- otherwise the program panics (ref/from-rc requires unique rc ...).

rthe rc to convert (consumed)

A ref<T> holding the value.

(let [x (ref/from-rc (rc/of 11))] (deref x))  ; => 11
builtin

weak

(weak [r :rc<T>] :weak<T>)

a non-owning observer of an rc.

The weak<T> holds no strong count, so it never keeps the value alive. rc/downgrade (tur/weak) is the same operation, with weak/upgrade, weak/alive? and weak/drop to use and release it.

rthe rc to observe (not consumed)

A weak<T> on the same cell.

builtin

upgrade

(upgrade [w :weak<T>] :nil)

retired: use weak/upgrade (tur/weak).

It returned the option as a ptr<void> that no Option function accepts, and the strong handle it took on success could not be released. It is now a compile error naming its replacement: weak/upgrade returns an (Option rc<T>), whose some holds a strong handle the caller releases with rc/drop (take it out with weak/unwrap).

wthe weak to upgrade

Nothing: a call does not compile.

builtin

weak?

(weak? [x :T] :bool)

is a value a weak<T>?

Answered from the argument's static type, on both engines, like ref?.

xany value

true iff x is a weak<T>.

(let [r (rc/of 1) w (weak r)] (weak? w))  ; => true
(weak? 3)                                 ; => false