Why Is It Not Possible to Shadow a Local Variable in a Loop

How bad is redefining/shadowing a local variable?

I noticed there were a lot of errors where a local variable was redefined inside a function for example.

You are not demonstrating redefining here. You show an example of variable shadowing.

Variable shadowing is not an error syntactically. It is valid and well defined. However, if your intention was to use the variable from the outer scope, then you could consider it a logical error.

but can the compiler really mess things up

No.

The problem with shadowing is that it can be hard to keep track of for the programmer. It is trivial for the compiler. You can find plenty of questions on this very site, stemming from confusion caused by shadowed variables.

It is not too difficult to grok which expression uses which variable in this small function, but imagine the function being dozens of lines and several nested and sequential blocks. If the function is long enough that you cannot see all the different definitions in different scopes at a glance, you are likely to make a misinterpretation.

declaration of 'count' hides previous local declaration 

This is a somewhat useful compiler warning. You haven't run out of names, so why not give a unique name for all local variables in the function? However, there is no need to treat this warning as an error. It is merely a suggestion to improve the readability of your program.

In this particular example, you don't need the count in the outer scope after the inner scope opens, so you might as well reuse one variable for both counts.

Is it worth it to change and fix the variable names

Depends on whether you value more short term workload versus long term. Changing the code to use unique, descriptive local variable names is "extra" work now, but every time someone has to understand the program later, unnecessary shadowing will increase the mental challenge.

What is the pythonic way to avoid shadowing variables?

The fact that the local variable (and function parameter) age happens to have the same name as a variable somewhere else in your program is irrelevant. The whole point of local variables is that they only live within the local scope of the function they're defined in.

The fact that the local variable has the same name as the variable used elsewhere as an argument is especially not a problem. In fact, it's very common in real-life code. For example, picking a random stdlib module, the 3.3 version of cmd, the Cmd.onecmd method has a variable named line, and it passes it as an argument to the self.default method, which binds it to a parameter that's also named line.

The fact that the variable used for the argument happens to be a global variable that you could have accessed, if you didn't have a local variable of the same name, is not a problem unless you actually wanted to access that global variable. Which you didn't want to in your existing code, and almost never should want to. In this case, and in most real-world cases, it's simply a coincidence that means nothing and affects nothing, not a problem you have to solve.


The problem you're having is that PyCharm can't guess whether you wanted the global age to be accessible in whenadult. Is it possible (if not in this trivial case, maybe in more complex cases) that a human might be similarly confused, slowing down his comprehension of your code? Or that you'll one day have to write code in some environment where your code reviewers or teacher or whatever will reject your code because it doesn't pass some linter with no warnings? Maybe.

But really, in any such environment, they'd probably complain about you using global variables in the first place. And you really don't need to here. The only reason age is a global is that it has to be accessible to the top-level code. If you move that code into a function, age can become a local in that function. For example:

def whenadult(age):
return 18 - age

def main():
age = 5
needtowait = whenadult(age)

main() # possibly with an if __name__ == '__main__' guard

This will make PyCharm happy, and any linter tools, and any easily-confused or rigidly-minded human readers. It'll even make your code a tiny bit faster. On the other hand, it's more code to read—only three lines and one indent, but then the whole program is only eight lines long. So, it's a tradeoff that you can make on a case-by-case basis.

declaration shadows a local variable in c

Within the compound statement of the do-while loop you need to use the same variable answer that is declared before the loop.

char answer;
do
{
answer = get_char("are you okay Y/N ");
if (answer == 'y' || answer == 'Y')
{
printf("you are okay");
}
else if (answer == 'n' || answer == 'N')
{
printf("you are not okay ");
}

}
while (answer != 'y' && answer != 'Y' && answer != 'n' && answer != 'N');

Otherwise this declaration within the compound statement of the do while loop

    char answer = get_char("are you okay Y/N ");

hides the declaration of the variable with the same name before the while loop and moreover this variable is not alive outside the loop.

Pay attention to that the do-while loop is defined in C the following way

do statement while ( expression ) ;

For example you may write

do ; while ( expression );

where a sub-statement of the do-while statement is the null statement ;.

If you use a compound statement as the sub-statement like

do { /*...*/ } while ( expression );

then this compound statement forms its one scope and all variables with automatic storage duration are not alive outside the compound statement.

Also instead of call printf like this

printf("you are okay");

it is better to use a call of puts like

puts("you are okay");

because the call of puts also appends an output of the new line character '\n'.

Get warning when a variable is shadowed

Both gcc and clang support the -Wshadow flag which will warn about variables that shadow one another. For example the warning I receive from gcc for your code is the following:

warning: declaration of ‘n’ shadows a previous local [-Wshadow]
for (int n = 1; n <= 10; n++){
^
warning: shadowed declaration is here [-Wshadow]
int n = 3;
^

gcc documents the flag here and says:

Warn whenever a local variable or type declaration shadows another
variable, parameter, type, class member (in C++), or instance variable
(in Objective-C) or whenever a built-in function is shadowed. Note
that in C++, the compiler warns if a local variable shadows an
explicit typedef, but not if it shadows a struct/class/enum.

In Visual Studio this looks like it was not possible before but seems to be fixed in recent versions.

Why does local variable inside foreach loop conflict with variable declared outside the loop?

While you can only refer to the outer foo after you declared it, locals are allocated at the beginning of a function which means the inner foo will overshadow the outer one, even if it hasn't been declared yet.

Java static variables and local variables

The local variable hides the original static field somewhat, but it is not inaccessible:

Test.x

And for non-static fields:

this.x // not in this case

So it is allowed, and in effect one often sees:

public class Pt {
private final int x;
public Pt(int x) {
this.x = x;
}
}

Which prevents the need to introduce some convention (_x, mX).

What is not allowed:

void f() {
int x = 42;
if (true) {
int x = 13; // COMPILER ERROR
...
}
}

As this is bad style, causing confusion.



Related Topics



Leave a reply



Submit