I'm learning OCaml, and I'm a bit confused with the immutability of variables. According to the book I'm reading, variables are immutable. So far so good, but why on Earth can I do this:
let foo = 42
let foo = 4242
What am I missing??
I think the best way to explain is with an example. Consider this code (executed in the OCaml REPL):
# let foo = 42;;
val foo : int = 42
# let return_foo () = foo;;
val return_foo : unit -> int = <fun>
# let foo = 24;;
val foo : int = 24
# return_foo ();;
- : int = 42
The above code does the following:
42
to the name foo
.return_foo ()
that returns the value bound to foo
.24
to the name foo
(which hides the previous binding of foo
).return_foo ()
function, which returns 42
.Compare this with the behaviour of a mutable value (created using ref
in OCaml):
# let foo = ref 42;;
val foo : int ref = {contents = 42}
# let return_foo () = !foo;;
val return_foo : unit -> int = <fun>
# foo := 24;;
- : unit = ()
# return_foo ();;
- : int = 24
which:
42
and binds it to the name foo
.return_foo ()
that returns the value stored in the reference bound to foo
.24
in the reference bound to foo
.return_foo ()
function, which returns 24
.The name foo
is first bound to an immutable value 42
and later it is rebound to another immutable value 4242
. You can even bind the same name to variables of different types. In OCaml we are talking not about mutability of a variable, but about a mutability of a value. For example, if you bind foo
to an array of values, this would be the same name, but bound to a mutable data, so that the value of a variable can change in time. Finally, each new binding just hides the previous one, so the original foo is still bound to 42
, but it is invisible and will garbage collected.
Maybe a little example will clarify the idea:
let example () =
let foo = 42 in (* 1 *)
let foo = 4242 in (* 2 *)
let foo = [|42|] in (* 3 *)
foo.(0) <- 56 (* 4 *)
It might be easier to have the following mental model:
(*1*) +--------+
+----> | 42 |
+------------+ | +--------+
| +----+
| foo +----+ +--------+
| | +----> | 4242 |
+---------+--+ (*2*) +--------+
|
| (*3*) +--------+
+------------> |[| 42 |]|
(*4*) +--------+
On lines 1
and 2
we just bind a variable foo
to two different values. On line 3
we bind it to an array that contains one element. On line 4
, we change the value, and foo is still bound to the same value, but the value contains different datum.
I hope I didn't confuse you even more ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With