Redefining variables

I agree. I am being a bit extreme. If "a bit extreme" actually makes any sense. I mean, can something be "a bit maximum"?

I feel that if one invests years of ones life studying and practicing to become some kind of professional and earn some kind of reputation then there is no backseat. That is ones life one is writing off by giving in to unreasonable demands.

Or, if one is just hacking code for money then "meh, whatever".

I guess we all have to decide what values we have and where are standards are.

2 Likes

Simply speaking WE NEED that contract as far as i know. Covid was a bad beast for our business. It is a miracle that we can choose the language....

1 Like

I do sympathise with your predicament.

1 Like

The way I see the "no shadow" requirement is kind of like a color requirement for a bridge. It should cause no major change of structure but may make things hard to look at.

I have run into problems with overwriting variables with dynamically types languages many times over the years. I have only encountered a single problem which was due to shadowing in Rust, and this despite that I use it roughly a quadrillion times more often in Rust.

I would argue (simply through experience) that shadowing is bad and should be avoided for dynamically typed languages (which is kind of a dumb thing to say because the ability to change a type is sometimes a powerful tool in languages that support type inspection), but for statically and strongly typed languages it's far less of a problem.

With all that said, one doesn't actually need to use shadowing even if the language allows it.

2 Likes

The complete story is that initially that request was not in the document presented to us. But when we delivered the first demo of the software one of their programmers introduced a variable that, by an incredible coincidence, had the same name as an existing one, causing an obvious problem. It was a mistake on the part of that programmer, the problem could have been avoided obviously, but from that moment they decided to introduce that further limitation. Anyway, coming in topic, the "lints solution" seems reasonable to me.

I'm curious as to when the obvious problem showed up exactly. Was it at compile time due to a type check error or some such? Or did it survive until the code was tested?

By all means use a lint. It still seems unnecessary to me though.

3 Likes

For the record, you mean “the same name and the same type”, right? In any case for this problem, if you want to use that lint, I suppose you only need the #![warn(clippy::unrelated)] one.

Arguably, it might even be a good thing to rely on some clippy lint, because it forces/encourages usage of clippy in general which can help improve code quality. (Of course if Clippy is not wanted otherwise, you can technically allow/disable all the other lints, though you might want to keep at least the deny-by-default ones.)

1 Like

Isn't that what the word "redefine" means? To redefine a name is to introduce a second definition reusing the same name. I think it's a fine use of the word.

redefine: to define (something, such as a concept) again

What this of course doesn't do is to reassign the variable.

Well, the old variable still exists.

Since two variables with the same name are involved, it can obviously not be a case of “redefining a variable”. The only thing that's - temporarily - redefined is the (local) meaning of the variable name.

Looking up “redefine” I find some explanation of “to change the meaning of something”. So in this sense of the word, the identifier that is the variable name is redefined. Whether a variable is more than just its name is then a question of terminology. In Rust I would usually mean, by “variable”, something that has a name but also a fixed location in memory, etc. But in other fields, e. g. in mathematical logic, a variable is just the name, and meaning comes only separately through a variable assignment (function).

Everyday use of redefine also wouldn't necessarily imply the possibility that this change in meaning is only for a limited scope, but I guess that doesn't matter because in the original example with two variables in the same block in Rust, the shadowing lasts for the whole scope of the shadowed variable anyways.

1 Like

In mathematics, when I say "let A be the unit square", and later I say "from now on let A be the unit circle", I have redefined "A", even though the unit square still exists.

I think it's the same here. First you define x to be the first object, then you redefine x to be the second object, even though the first object still exists.

To redefine something doesn't necessarily mean you're destroying / dropping the old thing.

I see what you're saying. So it's "redefining a name", not "redefining the object". Agreed about that.

Question is, is a "variable" the name, or the object that the name refers to. I'm not sure about this, I could go both ways.

3 Likes

Right, this sounds all very consistent with what I wrote above. You redefined A, or x. But you also say “the first variable still exists” which means you interpret “variable” to be more than just the name x. Whereas in the mathematical example you said “the unit square still exists”, i. e. in that context, the concept of “variable” was more limited to just the name.

Whether or not the unit square really still exists once you no longer think about it or keep a usable name for it is probably a separate, philosophical, question. Also since mathematics is (usually) done in natural language, not in formal logic, the shadowing isn't perfect. You can always talk about “the previous meaning of A before we redefined it”. Well actually, perhaps an analogy in Rust would be the way in which macro hygiene can give you a way to say “the previous meaning of x” anyways.

let x = 1;
macro_rules! previous_x { () => { x } }
let x = 2;
println!("{} {}", x, previous_x!());
3 Likes

OK I can agree with this, a "variable" is usually used to mean the object on the stack, not just the name.

So the right way to say it would be "redefine variable name" (to be a different variable).

I don't think so, in math there is an unambiguous answer to "does the unit square exist" (yes). The "exists" quantifier has unambiguous meaning (in the context of a specific theory).

But agreed it's different in programming.

1 Like

Zicog
they had no problem at compile time. We had a var named x_counter e their programmer also defined one with exactly the same name in the same scope but with another value. This has resulted in a problem at run time leading to inconsistent results. Our code was very complex and badly organized, okay, it was a pre-pre-alpha version but this, according to them, was not acceptable anyway.

Coming from a C# background, I really love this.

I agree.

I didn't think it was odd, as I was used to C# locals shadowing class fields, but I like the extra flexibility this gives.

As for shadowing being a source of mistakes, I feel it prevents more mistakes by removing access to the original variable. In C# (and other languages) I've often seen a variable converted or otherwise manipulated and subsesquently stored in a differently named variable. Then somewhere later in a method someone mistakenly refers to the original variable, leading to hard to find bugs especially when there may be more than one intermediate variable. With shadowing, each new variable can re-use the same name even if they are different types, preventing later portions of a method from accessing any of the incorrect variables.

2 Likes

We have discussed these days with our customer on this point as well. Their final words: if you find a way to protect a variable when we deem it necessary, for us it is ok. I think lints may be viable.

1 Like

Given this revised requirement, you could also define all extension points in terms of passed-in functions or closures. That gives a clean, enforced boundary between your variables and theirs: They can only see the things you pass as arguments, and cannot affect the operation of your code except through return values or calling functions/methods.

1 Like