> A mutable variable is a memory slot that can be mutated, though.
No, that's a mutable value.
The variable is the lexical representation of a value. If you change which value your variable binds to, you have changed the representation of the variable; you have mutated it. The underlying values in memory have not changed, they are immutable.
> The variable is the lexical representation of a value. If you change which value your variable binds to, you have changed the representation of the variable; you have mutated it. The underlying values in memory have not changed, they are immutable.
I completely agree with you that values and variables are separate things. However, mutable variables are still memory slots that can be mutated, while immutable variables are not. The memory slot of a variable usually lives on the stack, and contains a pointer to a value that lives elsewhere in memory.
I think the difference will be clearer in a language that distinguishes between introducing a variable and setting a variable.
var foo = "abcd"; // introduce a new variable binding
foo := "xyz"; // set a variable
Here's an example of what you can do in a language that has mutable variables that you cannot do in a language that only supports shadowing bindings:
var strings = ["str1", "str2", "str3"];
var foo = "abcd";
for (string in strings) {
foo := string;
}
println(foo); // Prints out "str3"
In this case, foo itself is a memory slot that can be mutated, independently of the strings, which are immutable values. foo is a mutable slot in memory that can be updated to contain different pointer values.
Now, if you only have shadowing, you end up with this:
var strings = ["str1", "str2", "str3"];
var foo = "abcd";
for (string in strings) {
var foo = string;
}
println(foo); // Prints out "abcd"
Each iteration of the loop is introducing a new binding with the name foo, but it is not changing or removing the original binding of foo. It's just that within the loop, only the local binding is visible.
I think part of the confusion around Elixir is that it only supports introducing new bindings, but the syntax looks like it's setting the value of a variable.
Another example that will hopefully help clarify:
var foo = "abcd";
var bar = "xyz";
println(bar);
That example is nearly the same as this (and in terms of what the program does, it's identical):
var foo = "abcd";
var foo = "xyz";
println(foo);
The only difference is that in the second case, the first foo binding isn't visible after the second one has been introduced. At least conceptually, they both still exist, but because of scoping rules, there's no way to access the first one.
I think using Lisp syntax might help clarify, because it makes the binding scope explicit:
> unlike a value which is actually a thing sitting in a memory slot in your vm.A mutable variable is a memory slot that can be mutated, though.