OxL Reference

8.9 Software transactional memory

oxl
static balances: Map<AccountId, TVar<Money>> = …

atomic {
  let a = balances[from].get()
  check(a >= amt)                 // otherwise the transaction waits for a change and retries
  balances[from].set(a - amt)
  balances[to].update(.add(amt))
}
  • atomic { … } executes the body as a serialisable transaction over TVars. On a conflict the body is restarted.
  • The body MUST be pure (except TVar operations); calls with effects are a compile error.
  • check(cond) blocks the transaction until the read TVars change, if cond is false.
  • atomic(db) { … } is different: a database transaction (§11.2).
  • A nested atomic (including through a called function) joins the outer transaction. The body of atomic is an expression: its value is the result of the run that committed. A panic or cancellation inside atomic discards the writes of the transaction and propagates; a task waiting in check is a cancellation point (§8.6).
  • TVar outside atomic. An operation on a TVar outside an atomic block is a separate one-operation transaction: get and set are atomic, but the compound update and swap outside a block are not atomic as "read-modify-write"; for an atomic update they MUST be executed inside atomic { … }. check outside atomic is a panic. The Standard does not require an orElse operation (D-8052; DIV-009; D-7521..D-7524).

atomic-effects

See also

Source: docs/spec/oxl-standard.en.md