I can only support what gradbot said – when I need mutation, I prefer let mutable
.
Regarding the implementation and differences between the two – ref
cells are essentially implemented by a very simple record that contains a mutable record field. You could write them easily yourself:
type ref<'T> = // '
{ mutable value : 'T } // '
// the ref function, ! and := operators look like this:
let (!) (a:ref<_>) = a.value
let (:=) (a:ref<_>) v = a.value <- v
let ref v = { value = v }
A notable difference between the two approaches is that let mutable
stores the mutable value on the stack (as a mutable variable in C#) while ref
stores the mutable value in a field of a heap-allocated record. This may have some impact on the performance, but I don’t have any numbers…
Thanks to this, mutable values that use ref
can be aliased – meaning that you can create two values that reference the same mutable value:
let a = ref 5 // allocates a new record on the heap
let b = a // b references the same record
b := 10 // modifies the value of 'a' as well!
let mutable a = 5 // mutable value on the stack
let mutable b = a // new mutable value initialized to current value of 'a'
b <- 10 // modifies the value of 'b' only!