§Scope

Scope determines what one variable is referring to, and there are two categories of scope: lexical (static) scope and dynamic scope.

1
2
3
4
5
In languages with lexical scope (also called static scope), name resolution
depends on the location in the source code and the lexical context. In contrast,
in languages with dynamic scope the name resolution depends upon the program
state when the name is encountered which is determined by the execution context
or calling context.

Let’s look at some examples, which might make the above explanation more concrete.

public class Test {
    static int x = 1;

    static void g() {
        System.out.println(x);
        x = 2;
    }

    static void f() {
        int x = 3;
        g();
    }

    public static void main(String[] args) {
        f();
        System.out.println(x);
    }
}

This Java program prints ‘1’ and ‘2’.

using System.IO;
using System;

class Program
{
    static int x = 1;

    static void g() {
        Console.WriteLine(x);
        x = 2;
    }

    static void f() {
        int x = 3;
        g();
    }

    static void Main() {
        f();
        Console.WriteLine(x);
    }
}

This C# program prints 1 and 2.

print = console.log
var x = 1;
function g() { print(x); x = 2;}
function f() { var x=3; g();}

f();
print(x);

This JavaScript program prints 1 and 2.

x=1
function g () { echo $x ; x=2 ; }
function f () { local x=3 ; g ; }
f
echo $x

This Bash program prints 3 and 1.

Most PL uses lexical scope, fortunately.

§Closure

Even if the rule for scoping is defined, there would still be different interpretation on the lexical environment for closures.

In some PL, variables are captured “by value”, eg. Java, while in some other PLs, variables are captured “by reference”, such as C# and JavaScript.

public class HelloWorld {
     public static void main(String []args){
        int x = 0;
        Runnable r = () -> System.out.println(x);
        x = 1;
        r.run();
     }
}

This Java program doesn’t compile, for the variable accessed inside the closure is not final or effectively final.

using System.IO;
using System;

class Program
{
    static void Main() {
        var x = 0;
        Func<int,int> f = y => x + y;
        x = 1;
        Console.WriteLine(f(1));
    }
}

This C# program prints 2.

print = console.log
x = 0

f = ->
    print x

x = 1

f()

This CoffeeScript program prints 2.

§Reference

Stackoverflow CSharp