I can’t help but think the real stars of the show are the let
and let mut
keywords: with, perhaps, a fairly valid complaint that an “immutable variable” is a fucking stupid and self-contradictory term. Variables vary, if they don’t they’re constants, and I’ve seen people turned off Rust because of this. But that’s really a problem for computer science as a whole. Like calling a variable-length list of same-typed items a Vector.
Consider the following slightly-overengineered fizzbuzz body, in Python and Rust.
Python
def fizzbuzz(n):
s = ""
if n % 3 == 0:
s += "fizz"
if n % 5 == 0:
s += "buzz"
if s == ""
s += str(n)
print(s)
Rust
fn fizzbuzz(n: usize) {
let mut s = String::new();
if n % 3 == 0 {
s += "fizz";
}
if n % 5 == 0 {
s += "buzz";
}
if s.len() == 0 {
s += n.to_string();
}
println!("{}", s);
}
Look the same to me, this would pass most reviews. So, what happens?
Ah.
Two things you’ll notice - one, the statically-typed Rust has only one actual type declaration here. Type inference is nice. Second, mutability is a feature of Python’s type system, which interplays with assignment and scope in a weird way. The two +=
operators are doing very different things. In python, the string is immutable, and +=
desugars to:
s = s + "fizz"
Which declares a new s, valid only in the scope of the conditional block, then, because it’s only valid in the scope of the conditional block, throws it away. If you printed a debug statement just after this assignment (but within the conditional) - you’d see fizz appearing, then disappearing!
In Rust, you can “variable shadow” - aka declare a new s
, without changing the old s - as much as you want. But you’ll need that let
keyword, so it’s obvious what you’re doing.