ref's (references) allow you to make any type of value mutable (sort of).
More properly, ref's are an abstraction of the concept of an "updateable location" which can be initialized to any value: like a memory cell
Three initialized references: ref true, ref 0, ref "foo"
(You can't create an uninitialized reference: this helps prevent bugs.)
A ref is a first-class value -- you can store it in a data structure, pass it to a function, and return it from a function.
A ref is much like a pointer in C or C++, but it's safe.
Suppose you have a ref that you have initialized to a Boolean -- e.g., let eof = ref false. eof is not a Boolean. It's value is not false. It is a ref (location) whose value is the Boolean false.
If you have a ref and want to get at its value, you have to dereference it with the prefix ! operator.
!eof = false, !(ref false) = false (tests for equality, not assignments!)
Some languages use a dereferencing operator for all their variables, like the shell or tcl:
sh | foo="bar"; echo $foo |
---|---|
tcl | set foo "bar"; puts $foo |
ocaml | let foo = ref "bar" in print_string !foo |
You can update the value of a ref with an assignment statement: eof := true, n := !n + 1
Now we can understand the cat program's while loop:
let eof = ref false in while not !eof do let len = input chan buffer 0 size in if len > 0 then print_string (String.sub buffer 0 len) else eof := true done