Redefining variables

Hi all.
This is simple ... or not...

C#

int x = 0;
int x = 1;

compiler does not allow:

CS0128 – A local variable named x is already defined in this scope

RUST:

let x = 0;
let x = 1;

this is ok. Why this choice? My boss (he is not a professional programmer) says this could be dangerous behavior because you could unintentionally re-define a variable you don't want
What do you think?
Thx.

1 Like

FYI, it doesn’t really redefine the variable. Technically, it merely introduces a second variable with the same name; but there’s also a rule called “shadowing” that says that when resolving a name where multiple local variables with that name are in scope, the one with the shortest/innermost scope is the one that’s picked.

Note that that means that after the scope of one variable ends, x refers to the other one again, e.g. with nested blocks:

fn foo() {
    let x = 1;
    {
        println!("{x}"); // "1"
        let x = 2;
        println!("{x}"); // "2"
    }
    println!("{x}"); // "1"
}

Similarly, when local and non-local items with the same name are in scope, the local one is picked, e.g.

fn f() { println!("fn f") }
fn g() {
    f(); // "fn f"
    let f = || println!("closure f");
    f(); // "closure f"
}

Even C# has some degree of this kind of behavior, just not for local variables vs. other local variables. E.g. I could find this code example online demonstrating how local variables can shadow class fields.

class Program
{
    int x = 0;

    void foo()
    {
        int x = 0;
        x = 1;
        
        Console.WriteLine(x);
    }
}
10 Likes

This is known as "shadowing". As if your original variable is lost in the shadow of the new definition.

Over many decades shadowing has been regarded as a bad thing in many languages that should be avoided as it is error prone. Without much thought I went along with this rule and was surprised to find it was perfectly fine in Rust.

As it happens I now think it's a useful Rust feature and a silly folklore rule.

Now I can create something/get something in one type and then convert it for use as a different type without having to worry my head about thinking up different names for the same thing in different types. A contrived example:

let id = something.get_id(params);
// Do something with 'id' as `String` here
...
let id = look_up(id);
// Do something with `id` as `u64` here

Practically I have yet to have shadowing cause an error that does not show up immediately as a type check failure or very soon as a test failure. Either way the problem is easily found and fixed.

Perhaps my change of view on shadowing is down to the strict type checking of Rust.

We don't have to do that ugly thing we see in C++ when a class contains an x and a method on a class then has something like m_x so as to avoid shadowing.

Rust causes one to rethink a lot of such programming folklore of old.

14 Likes

Most important to me is that it allows writing code like

if let Some(user) = user {
    //
}

When you use enums instead of nulls and sentinel values, shadowing makes code look a lot nicer and doesn't make you invent contrived names for variables. I remember writing a lot optionX variables when trying to use Optionals in Java, and just yesterday in Elm I started writing the equivalent of

if let Some(u) = user {
    //
}

due to the language disallowing shadowing.

7 Likes

hah, that’s interesting. Haskell does support shadowing for something like

val = Just 42
demo = case val of
  Just val -> val + 1
  Nothing -> 0

but apparently Elm doesn’t.

Edit: Wait or is that just a warning from the linter and not an error?

Edit2: Nope, seems like it’s really (and deliberately) disallowed.

2 Likes

I have heard this concern before, but it is not actually a real problem in practice.

For the record, anyone who doesn’t want to have shadowing in their code, there’s three clippy lints that can warn about (different cases of) shadowing if you activate them

Apparently (based on a quick test), they don’t seem to report on my example above of shadowing a function with a closure.

5 Likes

Coming from C/C# i have to adapt my mind to this behavior.... Interesting.... Anyway, as for our requirements, is there a way to locally lock an item? that is to make the "x" untouchable? For example using const keyword may be a good way?
thx

If you do not use mut in the variable declaration then it cannot be mutated. That is it cannot be changed. Same like using const in other languages.

The clippy lints described above will save you from most "shadowing" if you need it.

What actually is your requirement in this case?

1 Like

The boss has accepted a complicated order and we are trying to evaluate Rust as the programming language behind the project. Subsequently, our code will be taken over by the client company which, among the requisites, has imposed that cases such as those described in the initial example I have proposed cannot occur. So no shadow effect on variables in the same scope. Don't ask me why ... they pay, we have to do as they tell us ....

Sounds insane, but you can configure clippy to emit an error when you shadow something using the lints that @steffahn mentioned.

4 Likes

Sounds daft to me.

I appreciate that the client wants good quality software. As correct as can be. I presume you want to deliver good quality software. But some arbitrary, historical, rule may well cause the project to adopt a language that is far more error prone and likely to result in lesser quality software.

I have a little moral/philosophical problem with that statement.

As professional engineers we should not accept that (If indeed most of us can even dare to call ourselves "engineers")?

Should a civil engineer deliver a weak bridge, risking human life, because the client does not want to pay for a good job?

Should doctors give patients whatever suspect medicines they demand in order to get their money, never mind what effect those treatments have?

Heck, I cannot even get an electrical inspector to approve my installing a socket in the house now a days.

Should we just churn out whatever garbage is asked for just to get the money?

Perhaps I'm lucky in being old enough to say no. If one does not have pride in ones work what is ones life worth?

6 Likes

Yes, it's a good point. Anyway const makes the work in some situations.... and yes it's insane.

Zicog,
We strongly suspect that their actual skill on what they are talking about is not entirely solid, consistent, that required is just one of a series of strange impositions. Among other things, I should deal with network configuration rather than the programming part. However, it appears that we are not in a position to negotiate.

Using const is not a solution. The const keyword can only be used for compile-time constants. Just use let with those lints turned on.

5 Likes

I have already informed my group about the possibility offered by lints :wink:

I can imagine that is so.

After all, a typical patient knows less about what is wrong with them and how to treat it than the doctor they are consulting.

Never mind "negotiate". Your boss can always say we will only do what is right and within our competence.

If your boss does not, you can.

Perhaps I sound a bit harsh here. But I say it because I really regret giving in to such diktats on occasion during my career. Wishing that I had the wisdom and spinal fortitude to say "no" and just quit and move on at the time. There is no pride to be had in shoddy work, no matter how much money is on offer.

const is not a "non-variable variable". It's more like #define in C - the expression defining it is copied wherever it's used, so the value is created fresh every time (well, it may be optimized out, but semantically it's what I've said).

We will see what it will be possible to do. I would like to gain experience in a similar project with Rust.

That's a bit extreme. At least, I think "professional pride" is a very narrow, one-dimensional lens through which to evaluate a human life. There are times in life when one does have to make hard decisions and professional pride may well have to take a backseat to other concerns. And there are parts of the world where decent jobs are few and far between. We don't know OP's situation.

That said... @Rejkland, the client sounds like a nightmare. Unskilled people dictating to programmers how to do their job is enough sign of a dysfunctional organization. When that graduates to dictating to other companies' programmers how to do their job, you can be sure this won't be an isolated incident - the client is accustomed to making unreasonable requests and you can expect even more unreasonableness from them in the future. And if your own management is unable or unwilling to step in and defend you from these ridiculous power games, it sounds like an environment to escape from with all reasonable speed. Best of luck.

5 Likes