Well the declarations do look different, but that's by design, to indicate that one is an owned variable and the other is a reference parameter (it doesn't even use let).
I agree a better language is possible, perhaps even one where local variables and pass-by-reference parameters use the same exact notation somehow.
Is this relevant to the topic at all? I thought we were discussing whether "immutable variables" was an oxymoron.
As far as the abstract machine is concerned, there is no difference in semantics (this is what I read "the program" to mean). It's the same as the difference between:
/// Rolled some dice. May need reconsidering in the future.
const THE_ANSWER: usize = 47;
// and
/// Empirically determined by pulling tiles from a bag. Do not alter.
const THE_ANSWER: usize: 42;
The program semantics are the same; the source semantics are not.
I find this lament strange, I don't think it's reasonable to wish for such a concept of immutability. Consider the following snippets (which represent more a mental image of a code being skimmed rather than a physical piece of code):
Are the foos referring to the same thing? Eeven with "deep immutability", we don't know, there could be one per each block or one in the outer block, we'd have to check.
{
// code
{
// lots of code... we don't see the top from down here
foo = bar;
}
foo();
}
We don't know here either.
Names can refer to different things in different places, such is life, and IMO trying to prevent this ends up leading to more confusion rather than less. For this reason, I like Rust's shadowing, the result seems easier to reason about in the end.
The only thing I find unfortunate (in Rust) is that when you do stuff like
let x = String::from("abc");
let x = 9001;
// code...
}
it's not readily clear at what point the string is de-alloc'd, you have to remember the drop rules, and they aren't intuitive. (I know there are some reasons for that, but still.)
I was careful to keep adding "in the scope" every time I mentioned it, because I expected this reply. You've created a situation that doesn't establish the scope.
{
let foo = 1;
// this is the scope of foo now
{
foo // yes, it's 1
}
{
foo.apply() // yes, it's still 1
}
}
// the scope ends, `foo` may be anything here
Scope is a fundamental part of the syntax, and I take it as an axiom that it's sufficiently clearly delimited and readable, as otherwise nothing in the C-like syntax can work.