Skip to content
Part IA Michaelmas Term

References

The three reference primitives

SyntaxTypeEffect
ref E'a -> 'a refCreate a new reference cell with initial contents = value of E
!P'a ref -> 'aReturn current contents of reference P (dereference)
P := E'a ref -> 'a -> unitUpdate contents of P to value of E

Using references

let p = ref 5
(* val p : int ref = {contents = 5} *)

p := !p + 1
(* : unit = ()  -- p now holds 6 *)
  • ref 5 allocates a new memory location, initially holding 5.
  • !p reads the current contents (dereferencing).
  • p := ... updates the contents, returning ().

References and mutation

Important distinctions

  • let bindings are immutable. p will always refer to the same reference cell unless shadowed by a new declaration.
  • Only the contents of the cell is mutable.
  • The type int ref is distinct from int. You cannot assign to a plain int variable.
  • OCaml displays reference values as {contents = v}, which is readable but does not reveal whether two references holding the same value are the same cell.

Lists of references

let ps = [ref 77; p]
(* val ps : int ref list = [{contents = 77}; {contents = 6}] *)

List.hd ps := 3
(* : unit = () *)

ps
(* : int ref list = [{contents = 3}; {contents = 6}] *)

The assignment List.hd ps := 3 updates the contents of the first reference in the list. It does not modify the list ps itself - only the cell that the first element points to.

Explicit vs implicit dereference

OCaml requires explicit dereferencing with !. Most conventional languages make dereferencing implicit: on the left of =, a variable denotes a location; on the right, it denotes the contents. While implicit dereferencing makes programs shorter, it is logically messy. OCaml’s explicitness makes it ideal for teaching.

OCamlConventional equivalent
let p = ref 5int p = 5
p := !p + 1p = p + 1
!pp (in an expression)