# Name Shadowing Should Be An Operator

I recently discovered that in Rust, this is a relatively common operation:

let foo = String::from("foo");
// stuff that needs ownership
let foo = &foo;


Or this:

let mut vec = Vec::new();
vec.push("a");
vec.push("b");
let vec = vec; /* vec is immutable now */


This is a particularly permissive form of name-shadowing, which allows you to re-declare a variable in an inner scope that shadows the name of a variable in an outer scope, making the outer variable inaccessible. Almost every single programming language in common use allows you to do this in some form or another. Rust goes a step further and lets you re-declare a variable inside the same scope as another variable.

This, to me, is pretty terrifying, because name-shadowing itself is often a dangerous operation. 90% of the time, name-shadowing causes problems with either temporary or index variables, such as i. These are all cases where almost you never want to name-shadow anything and doing so is probably a mistake.

for(int i = 0; i < width; ++i)
{
for(int j = 0; j < height; ++j)
{
//
// lots of unrelated code
//

float things[4] = {1,2,3,4};
for(int i = 0; i < 4; ++i)
box[i][j] += things[i] // oops!
//      ^ that is the wrong variable!
}
}


These errors almost always crop up in complex for loop scenarios, which can obviously be avoided with iterators, but this isn't always an option, espiecally in a lower-level systems programming language like Rust. Even newer languages like Go make it alarmingly easy to name-shadow, although they make it a lot harder to accidentally shoot yourself because unused variables are a compiler error:

foo, err := func()
if err != nil {
err := bar(foo) // error: err is not used
}
println(err)


Unfortunately, Rust doesn't have this error, only an unused-variables linter warning. If you want, you can add #![deny(clippy::shadow_unrelated)] to be warned about name-shadowing. However, a lot of Rust idioms depend on the ability to name-shadow, because Rust does a lot of type-reassignment, where the contents of a variable don't change, but in a particular scope, the known type of the variable has changed to something more specific.

let foo = Some(5);
match foo {
Some(foo) => println!("{}", foo),
None => {},
}


Normally, in C++, I avoid name-shadowing at all costs, but this is partially because C++ shadowing rules are unpredictable or counter-intuitive. Rust, however, seems to have legitimate use cases for name-shadowing, which would be reasonable if name-shadowing could be made more explicit.

I doubt Rust would want to change it's syntax, but if I were to work on a new language, I would define an explicit name-shadowing operator, either as a keyword or as an operator. This operator would redefine a variable as a new type and throw a compiler error if there is no existing variable to redefine. Attempting to redefine a variable without this operator would also throw a compiler error, so you'd have something like:

let foo = String::from("foo");
// stuff that needs ownership
foo := &foo;

Or alternatively:
let mut vec = Vec::new();
vec.push("a");
vec.push("b");
shadow vec = vec; /* vec is immutable now */


While the := operator is cleaner, the shadow keyword would be easier to embed in other constructions:

let foo = Some(5);
match foo {