The Iris Tutorial in Lean

4.4. References🔗

References are dynamically allocated through the ref(_) construct. Given a value, ref(_) finds a fresh location on the heap and stores the value there. The location is then returned.

def alloc : Exp := hl( let l1 := ref(#0); let l2 := ref(#0); (l1, l2))

After allocation, we can read and update the value at the returned location l with !l and l ← v, respectively. (The Rocq port spells the store as l <- v; iris-lean uses the left-arrow .)

def load : Exp := hl( let l := ref(#5); !l) def store : Exp := hl( let l := ref(#5); l #6; !l)

To allow for synchronisation between threads, HeapLang provides a single primitive called compare-and-exchange, written cmpXchg(l, v1, v2). This instruction atomically reads the contents of location l, checks if it is equal to v1, and, in case of equality, updates l to contain v2. The instruction returns a pair (v, b), with v being the original value stored at l, and b a boolean indicating whether the location was updated.

def cmpxchg_fail : Exp := hl( let l := ref(#5); cmpXchg(l, #6, #7)) def cmpxchg_suc : Exp := hl( let l := ref(#5); cmpXchg(l, #5, #7))

iris-lean also provides a variant of cmpXchg called compare-and-set, written cas(l, v1, v2). The only difference is that cas only returns the boolean.

-- TODO (upstream — iris-lean): use the unit literal in the success -- branches once the `hl` DSL gains a `#()` form (Rocq tutorial uses it). def cas_example : Exp := hl( let l := ref(#5); if cas(l, #6, #7) then #0 else let a := !l; if cas(l, #5, #7) then let b := !l; (a, b) else #0)

The Rocq tutorial returns the unit value #() from the success branches; we substitute #0 here for the same reason as in the if_then_else example above.