Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Variable shadowed" warning in lambda (when not captured)

Let's consider this code:

int main()
{
    int a = 1;

    auto f1 = [a]() {
        int a = 10;
        return a;
    };

    auto f2 = []() {
        int a = 100;
        return a;
    };

    return a + f1() + f2();
}

When using flag -Wshadow with gcc (tested on 10.2), we get these warnings:

<source>:26:13: warning: declaration of 'a' shadows a lambda capture [-Wshadow]
    6 |         int a = 10;

<source>:21:13: warning: declaration of 'a' shadows a previous local [-Wshadow]
   11 |         int a = 100;

I understand the first case, where we explicitly capture a, and thus are shadowing the original local. However, the second case is interesting, because if we remove declaration int a = 100; we get a compile error (= error: 'a' is not captured: return a;). Doesn't that "prove" that the declaration is not in the same scope as the original local, and thus we are not actually shadowing anything? Hence my question, whether the warning (for the second case) is indeed valid, or whether gcc is being a bit too strict here?

like image 574
Phil-ZXX Avatar asked Feb 28 '21 00:02

Phil-ZXX


People also ask

How do you avoid variable shadowing?

Variable shadowing could be avoided by simply renaming variables with unambiguous names. We could rewrite the previous examples: The inner scope has access to variables defined in the outer scope.

What does shadowing a variable mean?

In computer programming, variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. At the level of identifiers (names, rather than variables), this is known as name masking.

How can a global variable be shadowed?

When inside the nested block, there's no way to directly access the shadowed variable from the outer block. However, because global variables are part of the global namespace, we can use the scope operator (::) with no prefix to tell the compiler we mean the global variable instead of the local variable.


1 Answers

You are correct, lambda a doesn't shadow main::a because main::a isn't captured in the lambda, thus is not on scope there.

However I think about what the purpose of the shadow warning is: to avoid programmer confusion. If a long body of code if the programmer sees the outer declaration, but doesn't see the inner declaration he or she may incorrectly assume that a use of the inner variable refers to the outer variable. And this possible confusion still applies here, even if the variable doesn't tehnically shadow the outer one.

I don't know if this is the intention of the warning or if it is a bug. Or even if that is a compelling enough reason to have a warning even a differently worded one. Shadow warning are problematic anyways. You can find a lot of discussions and bug reports about shadow warning that even if tehnically correct are considered harmful.

like image 97
bolov Avatar answered Sep 20 '22 12:09

bolov