TRef — Transactional References

TRef<T> is the fundamental mutable cell in id_effect's STM system. It wraps a value that can be read and written inside transactions.

Creating a TRef

#![allow(unused)]
fn main() {
use id_effect::TRef;

let counter: TRef<i32> = TRef::new(0);
let balance: TRef<f64> = TRef::new(1000.0);
}

TRef::new(value) creates a transactional reference with an initial value. TRefs are typically created once (at startup or when initialising shared state) and then shared across fibers via Arc.

Transactional Operations

All TRef operations return Stm<_> — transactional descriptions, not effects. They only work inside stm! (or when run through commit/atomically):

#![allow(unused)]
fn main() {
use id_effect::{TRef, stm};

let counter = TRef::new(0);

// Read inside a transaction
let read_op: Stm<i32> = counter.read_stm();

// Write inside a transaction
let write_op: Stm<()> = counter.write_stm(42);

// Modify (read-write atomically)
let modify_op: Stm<()> = counter.modify_stm(|n| n + 1);
}

These are descriptions. Nothing happens until they're committed.

Running Inside stm!

The stm! macro provides do-notation for composing Stm operations, exactly like effect! does for Effect:

#![allow(unused)]
fn main() {
use id_effect::{stm, TRef};

let counter = TRef::new(0_i32);
let total   = TRef::new(0_i32);

let transaction: Stm<()> = stm! {
    let count = ~ counter.read_stm();
    let sum   = ~ total.read_stm();
    ~ counter.write_stm(count + 1);
    ~ total.write_stm(sum + count);
    ()
};
}

Sharing TRefs

TRefs are Clone + Send + Sync. Wrap in Arc to share across fibers:

#![allow(unused)]
fn main() {
use std::sync::Arc;

let shared: Arc<TRef<i32>> = Arc::new(TRef::new(0));

// Clone for each fiber
let clone1 = Arc::clone(&shared);
let clone2 = Arc::clone(&shared);

fiber_all(vec![
    increment_n_times(clone1, 1000),
    increment_n_times(clone2, 1000),
])
// Result: counter = 2000 (atomically, without locks)
}

TRef vs. Mutex

PropertyTRefMutex
Composable across updates
Deadlock-free
Blocking read✗ never✓ blocks writers
Works with I/O
Overheadretry costlock/unlock cost

Use TRef for short, composable state mutations. Use Mutex when you need to hold a lock across I/O (though ideally you redesign to avoid that).