Values and mutation
Everything in Xo is a value: assigning or passing a struct copies it (cheaply, because collections share structure). There are no pointers, so two parts of a program can never change the same value without synchronization, and data races cannot happen.
mutation/main.xo
struct Account { owner: Str, balance: Int }
fn (var a: Account) deposit(amount: Int) requires amount > 0 {
a.balance += amount
}
fn main(os: Os) {
var acct = Account{owner: "ada", balance: 10}
let snapshot = acct
acct.deposit(5)
os.stdio.println("now ${acct.balance}, snapshot ${snapshot.balance}")
var accounts: Map[Str, Account] = {"ada": acct}
accounts.update("ada", Account{owner: "ada", balance: 0}, fn(var a) { a.deposit(100) })
let stored = accounts.get("ada").map(fn(a) { a.balance }) ?? 0
os.stdio.println("stored ${stored}")
let hits = Atomic[Int].new(0)
let cache = Mutex[Map[Str, Int]].new({})
cache.with(fn(var m) { m.put("k", hits.add(1)) })
let size = cache.with_read(fn(m) { m.len() })
os.stdio.println("hits ${hits.get()}, cache ${size}")
}Output:
now 15, snapshot 10
stored 115
hits 1, cache 1
snapshotkept the old balance:acctandsnapshotare separate values.- A
varreceiver (fn (var a: Account)) changes the caller’s binding in place. m.update(key, init, fn(var v) { ... })changes a value inside a collection in one step. Copying a value out, changing it, and forgetting to store it back is a compile error (XO0520).Mutex[T]andAtomic[T]are the only shared mutable state.withgives the closure the value to change;with_readgives read only access shared with other readers.
Closures capture by value, so they cannot quietly change a local:
fn main(os: Os) {
var count = 0
let bump = fn() { count += 1 }
bump()
os.stdio.println("${count}")
}xo check says:
main.xo:3:21: error XO0502: assignment mutates `count`, which is captured by a closure; closures capture by value (core 3.3)
note: main.xo:2:7: `count` is declared here, outside the closure
note: to share mutable state with a closure, capture a `Mutex` or `Atomic` handle (core 5.4)
1 module(s), 1 error(s), 0 warning(s)