Variable shadowing

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. This outer variable is said to be shadowed by the inner variable, while the inner identifier is said to mask the outer identifier. This can lead to confusion, as it may be unclear which variable subsequent uses of the shadowed variable name refer to, which depends on the name resolution rules of the language.

One of the first languages to introduce variable shadowing was ALGOL, which first introduced blocks to establish scopes. It was also permitted by many of the derivative programming languages including C++ and Java.

The C# language breaks this tradition, allowing variable shadowing between an inner and an outer class, and between a method and its containing class, but not between an if-block and its containing method, or between case statements in a switch block.

Example

Lua

The following Lua code provides an example of variable shadowing, in multiple blocks.

v = 1 -- a global variable

do
    local v = v + 1 -- a new local that shadows global v
    print(v) -- prints 2

    do
        local v = v * 2 -- another local that shadows outer local v
        print(v) -- prints 4
    end

    print(v) -- prints 2
end

print(v) -- prints 1

Python

The following Python code provides another example of variable shadowing:

x = 0

def outer():
    x = 1

    def inner():
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# prints
# inner: 2
# outer: 1
# global: 0

As there is no variable declaration but only variable assignment in Python, the keyword nonlocal introduced in Python 3 shall be used to avoid variable shadowing and assign to non-local variables:

x = 0

def outer():
    x = 1

    def inner():
        nonlocal x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# prints
# inner: 2
# outer: 2
# global: 0

The keyword global shall be used to avoid variable shadowing and assign to global variables:

x = 0

def outer():
    x = 1

    def inner():
        global x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# prints
# inner: 2
# outer: 1
# global: 2

Rust

fn main() {
    let x = 0;
    
    {
        let x = 1;
        println!("Inner x: {}", x); // prints 1
        
    }
    
    println!("Outer x: {}", x); // prints 0
    
    // Shadow
    let x = "Rust";
    println!("Outer x: {}", x);  // prints 'Rust'
}

# Inner x: 1
# Outer x: 0
# Outer x: Rust

C++

#include <iostream>

int main()
{
  int x = 42;
  int sum = 0;

  for (int i = 0; i < 10; i++) {
    int x = i;
    std::cout << "x: " << x << '\n'; // prints values of i from 0 to 9
    sum += x;
  }

  std::cout << "sum: " << sum << '\n';
  std::cout << "x:   " << x   << '\n'; // prints out 42

  return 0;
}

Java

public class Shadow {
        private int myIntVar = 0;

        public void shadowTheVar(){

            // since it has the same name as above object instance field, it shadows above 
            // field inside this method
            int myIntVar = 5;

            // If we simply refer to 'myIntVar' the one of this method is found 
            // (shadowing a second one with the same name)
            System.out.println(myIntVar);

            // If we want to refer to the shadowed myIntVar from this class we need to 
            // refer to it like this:
            System.out.println(this.myIntVar);
        }

        public static void main(String[] args){
            new Shadow().shadowTheVar();
        }
    }

See also

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.