7.1. Refs#

A ref is like a pointer or reference in an imperative language. It is a location in memory whose contents may change. Refs are also called ref cells, the idea being that there’s a cell in memory that can change.

Here’s an example of creating a ref, getting the value from inside it, changing its contents, and observing the changed contents:

let x = ref 0;; 
val x : int ref =
- : int = 0
x := 1;; 
- : unit = ()
- : int = 1

The first phrase, let x = ref 0 , creates a reference using the ref keyword. That’s a location in memory whose contents are initialized to 0 . Think of the location itself as being an address—for example, 0x3110bae0—even though there’s no way to write down such an address in an OCaml program. The keyword ref is what causes the memory location to be allocated and initialized.

The first part of the response from OCaml, val x : int ref , indicates that x is a variable whose type is int ref . We have a new type constructor here. Much like list and option are type constructors, so is ref . A t ref , for any type t , is a reference to a memory location that is guaranteed to contain a value of type t . As usual, we should read a type from right to left: t ref means a reference to a t . The second part of the response shows us the contents of the memory location. Indeed, the contents have been initialized to 0 .

The second phrase, !x , dereferences x and returns the contents of the memory location. Note that ! is the dereference operator in OCaml, not Boolean negation.

The third phrase, x := 1 , is an assignment. It mutates the contents x to be 1 . Note that x itself still points to the same location (i.e., address) in memory. Memory is mutable; variable bindings are not. What changes is the contents. The response from OCaml is simply () , meaning that the assignment took place—much like printing functions return () to indicate that the printing did happen.

The fourth phrase, !x again dereferences x to demonstrate that the contents of the memory location did indeed change.

7.1.1. Aliasing#

Now that we have refs, we have aliasing: two refs could point to the same memory location, hence updating through one causes the other to also be updated. For example,

let x = ref 42;; let y = ref 42;; let z = x;; x := 43;; let w = !y + !z;;