Inquiring about idiomatic usage of shadowing


#1

I was trying to explain someone about mutability today when, instead they accidentally used shadowing.
e.g,
let x = 1;
let x = x + 1;

I’ve looked around to find more details about shadowing and why the above may or may not be a good idea. So far I’ve come across a post in a different thread and learned that Clippy can warn about such use.

I was wondering, (short of clippy warnings) is shadowing over mutability is an idiomatic usage or is it essentially foot-shooting? More importantly, is there a doc that gives more info about shadowing?


#2

Shadowing is generally considered totally fine. A lot of people have a visceral negative reaction to it, but then end up liking it in the end.

I personally prefer it to mutation, when it makes sense. It’s also great when you need to do two or three processing steps to something, and don’t want to come up with multiple, intermediate names.

http://doc.rust-lang.org/stable/book/variable-bindings.html#scope-and-shadowing


#3

This is actually very nice. I’ve been following the book and the example there made a lot of sense.

I’ve seen how mutation work in Rust gets explained in detail from @alexcrichton’s tech talk. Is there a difference is cost with shadowing? For example is memory allocation/deallocation different between the two?


#4

I use shadowing to convert variables, likes so (pseudo code)

let input: String = get_input();
let input: i64 = input.parse().unwrap();

This way, your code stays readable, without going crazy with variable names like input_str and input_int.

If it stayed the same type, then I would probably use mutation, but as my example, the type changes, so I would need to use shadowing.


#5

I would use shadowing if the value stays essentially the same, so it deserves to have the same name. The difference is then usually reflected in the type, so the type checker will prevent errors from confusing the two definitions.

In Rust that happens a lot, for example when you unpack options or results.

You can also use shadowing to build up a value and then make it immutable for further read-only access (the only use mentioned in the style guide https://doc.rust-lang.org/style/features/let.html#shadowing-fixme).


#6

Shadowing is especially useful when using Rc, Arc, or Mutex and other stuff from std::sync:

let value = ();

let value = Arc::new(Mutex::new(value));

thread::spawn(
{
    let value = value.clone();

    move||
    {
        let value = value.lock().unwrap();
    }
});

#7

I’ve always been in favor and am still in favor of printing a warning when the user shadows a variable without using the original variable in the declaration of the new one. In other words, the “shadow_unrelated” lint of clippy.

I’m using shadowing a lot, but shadowing without using the old variable is almost always a bug in your code (in fact I can’t find any example where it would be useful) and I’ve experienced bugs caused by this in more than one occasion.


#8

@tomaka by being unused you do also mean “not used in the shadowing statement”?