Part IA Michaelmas Term
References
The three reference primitives
| Syntax | Type | Effect |
|---|---|---|
ref E | 'a -> 'a ref | Create a new reference cell with initial contents = value of E |
!P | 'a ref -> 'a | Return current contents of reference P (dereference) |
P := E | 'a ref -> 'a -> unit | Update 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 5allocates a new memory location, initially holding 5.!preads the current contents (dereferencing).p := ...updates the contents, returning().
Important distinctions
letbindings are immutable.pwill always refer to the same reference cell unless shadowed by a new declaration.- Only the contents of the cell is mutable.
- The type
int refis distinct fromint. You cannot assign to a plainintvariable. - 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.
| OCaml | Conventional equivalent |
|---|---|
let p = ref 5 | int p = 5 |
p := !p + 1 | p = p + 1 |
!p | p (in an expression) |