4 ms·
I was part of the Reddit discussion linked in the article, and although I haven't had the time to think through the issues (nor do I have the same experience as
by gnuvince 12y ago
I was part of the Reddit discussion linked in the article, and although I haven't had the time to think through the issues (nor do I have the same experience as the Rust dev team), I'd like to offer some thoughts.
First, I am a big fan of functional programming, coming from OCaml and Haskell mostly and not so much experience writing software that needs to be as fast as possible. This definitely colours how I judge a language: all other things being equal, I will prefer a language that is closer to ML than to C. In most functional languages, if you want to a name to refer to a mutable cell, you need to declare it as such (let x = ref expr for OCaml, some sort of state monad in Haskell). I have grown to prefer to have as many of my variables be immutable as is practically possible: it feels like there are less moving parts in the program that can go wrong. This is a reason I was happy with Rust's initial design choice. I also quite enjoy the fact that you need to be explicit about your intent to have a variable refer to a mutable cell and that immutable is the default, unlike in languages like C or Java.
pcwalton asked what bugs immutable local variables help prevent, and honestly, I can't think of anything non-trivial. I can imagine some scenarios where a developer would get a compiler error instead of weird runtime behavior, for instance:
let mut i = 0;
let j = 0;
while i < 10 {
some_processing();
j += 1; // oops! meant i += 1;
}
If `let mut` is removed from the language, this piece of code would compile, but I suspect that it should be relatively fast and easy to spot the bug and fix it. However, as a programmer, I like that a simple keyword can help me reason about code without having to inspect a larger portion of the program (i.e. scan the block containing the definition to see if the variable is modified).
Another thing that immutable-by-default local variables seem to encourage (at least, they encourage me) is to approach problems in a more functional programming oriented way. For instance, let's say you want to find the x value such that f(x) gives the greatest result. You can use regular imperative programming:
let mut max = 0;
let mut max_result = 0;
for x in range(0, N) {
let y = f(x);
if y > max_result {
max = x;
max_result = y;
}
}
println!("f({}) = {}", max, max_result);
But maybe you'd look at the two mutable variables and think "maybe there's a higher-level way of doing this..." and you end up with:
let (max_result, max) = range(0, N)
.map( |x| (f(x), x) )
.max()
.unwrap();
println!("f({}) = {}", max, max_result);
(Hopefully I didn't make too many mistakes in the code.) Perhaps this style of programming doesn't need any encouragement, but for me, when I see mutable variables, I pause and consider for a moment if I couldn't perform the task in a manner that would be more declarative and less error-prone.
When I think about it, I can sort of see that it makes sense that mutability be linked to uniqueness: most problems with mutable variables comes from the fact that they can be modified in surprising ways. Though I must ask: if a reference can be mutated if you have the only reference to it, could there be cases when you want to have the only reference to a cell and still be unable to modify it (i.e. &mut const)?
Finally, I appreciate the practical implications for the compiler writers; I am part of the Sable lab at McGill where we work on a MATLAB compiler, and the crazy edges cases of Matlab are really a headache when doing any work in the system, and I can definitely understand wanting simpler semantics. If we want Rust to be a safe language, having a semantics that is simpler to implement and verify is definitely something important.
With that said, I'll re-read Niko's post (some parts, especially about closures, were not clear on my first read), and I hope that although this issue seems to be raising some passions, in the end the community and the dev team will figure out what works best for everyone and Rust will be stronger for it.
- pohl 12y agoI do like the comfort of being able to nail-down local things so that they don't move, as it were. The encouragement it provides is subtle, but i do appreciate it (especially on a large team, where colleagues span the full range of the talent spectrum). I think it's worth noting that even a very shallow notion of immutability would provide enough comfort for me. Compiler writers could call it a "syntactic blanky". https://en.wikipedia.org/wiki/Security_blanket https://en.wikipedia.org/wiki/Security_blanket Something along those lines shouldn't be mutually-exclusive with the current proposal, local reasoning being sufficient. Something like 'final' or 'const' (or, better still, replacing the 'let' keyword with 'val' and 'var' as in Scala.)