tur/forms/references
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. Arefbound byletis freed when its scope exits (or earlier, bydrop!), 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/cloneadds an owner andrc/dropreleases one; anrcbound byletis released at scope exit. Field access reads through it:(.x r)on anrc<Point>.weak<T>observes anrc<T>without owning it -- the way to break anrccycle.
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.
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.
| x | the initial value |
A ref<T> owning a fresh cell.
(let [r (ref 42)] (deref r)) ; => 42
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.
| r | the 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
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.
| r | the reference to free (consumed) |
(let [r (ref 7)] (let [v (deref r)] (drop! r) v)) ; => 7
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.
| x | any value |
true iff x is a ref<T>.
(let [r (ref 7)] (ref? r)) ; => true (ref? 7) ; => false
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.
| x | the initial value |
An lref<T> owning a fresh cell.
(let [p (lref/new 99)] (deref p)) ; => 99
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).
| x | the value to share |
An rc<T> with strong count 1.
(let [r (rc/of 42)] (deref r)) ; => 42
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.
| r | the 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
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.
| r | the handle to release (consumed) |
(let [r (rc/of 42) s (rc/clone r)] (rc/drop s) (rc/strong-count r)) ; => 1
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.
| r | the rc to inspect |
The strong count.
(let [r (rc/of 42)] (rc/strong-count r)) ; => 1
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).
| r | the rc |
A ptr<void> to the value.
(let [r (rc/of 5)] (unsafe (ptr-deref (rc->ptr r)))) ; => 5
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.
| r | the ref to convert (consumed) |
An rc<T> holding the value.
(let [r (rc/from-ref (ref 9))] (deref r)) ; => 9
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 ...).
| r | the rc to convert (consumed) |
A ref<T> holding the value.
(let [x (ref/from-rc (rc/of 11))] (deref x)) ; => 11
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.
| r | the rc to observe (not consumed) |
A weak<T> on the same cell.
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).
| w | the weak to upgrade |
Nothing: a call does not compile.
weak?
(weak? [x :T] :bool)
is a value a weak<T>?
Answered from the argument's static type, on both engines, like ref?.
| x | any value |
true iff x is a weak<T>.
(let [r (rc/of 1) w (weak r)] (weak? w)) ; => true (weak? 3) ; => false