Semantics of let
assignment in Nim
I was recommended the Nim programming language and started reading through the Tutorial 1, the Manual and even the memory model (in particular the section about strings and seqs).
I soon encountered some strange behavior regarding let
assignment which doesn't seem to make any sense at all, to the point of appearing a complete mess. I can demonstrate all the nonsense with this simple script (link to playground):
echo "first example:"
proc p =
var msg = "Hello"
let copy = msg
msg.add(" World!")
echo msg
echo copy # does NOT change
p()
echo "\nsecond example:"
proc q =
var msg = "Hello"
let copy = msg
msg.add("!")
echo msg
echo copy # DOES change
q()
echo "\nthird example:"
var msg = "Hello"
let copy = msg
msg.add("!")
echo msg
echo copy # does NOT change
In the first and third examples, copy
retains the original value "Hello"
. The second example (proc q
) shares a similarity with the other two cases:
- it is similar to the first because it employs the local scope of a
proc
, - it is similar to the third because it appends the same string (
"!"
).
For some arcane reason however, in the first and third examples copy
is indeed a copy (bind by value?), whereas in the second example the modification to the variable msg
propagates to the immutable copy
(bind by reference?).
What is going on? How can we make sense of this? Does let
bind by value or by reference? If it make sense somehow, why is it not explained clearly and in depth in the official guides?