CSE 341 -- Static and Dynamic Scoping

Scope rules define the visibility rules for names in a programming language. What if you have references to a variable named k in different parts of the program? Do these refer to the same variable or to different ones?

Most languages, including Algol, Ada, C, Pascal, Scheme, and Haskell, are statically scoped. A block defines a new scope. Variables can be declared in that scope, and aren't visible from the outside. However, variables outside the scope -- in enclosing scopes -- are visible unless they are overridden. In Algol, Pascal, Haskell, and Scheme (but not C or Ada) these scope rules also apply to the names of functions and procedures.

Static scoping is also sometimes called lexical scoping.

Simple Static Scoping Example


    begin
    integer m, n;

    procedure hardy;
        begin
        print("in hardy -- n = ", n);
        end;

    procedure laurel(n: integer);
        begin
        print("in laurel -- m = ", m);
        print("in laurel -- n = ", n);
        hardy;
        end;

    m := 50;
    n := 100;
    print("in main program -- n = ", n);
    laurel(1);
    hardy;
    end;
The output is:
in main program -- n = 100
in laurel -- m = 50
in laurel -- n = 1
in hardy -- n = 100    /* note that here hardy is called from laurel */
in hardy -- n = 100    /* here hardy is called from the main program */

Blocks can be nested an arbitrary number of levels deep.

Dynamic Scoping

Dynamic scoping was used in early dialects of Lisp, and some older interpreted languages such as SNOBOL and APL. It is available as an option in Common Lisp. Using this scoping rule, we first look for a local definition of a variable. If it isn't found, we look up the calling stack for a definition. (See Lisp book.) If dynamic scoping were used, the output would be:
in main program -- n = 100
in laurel -- m = 50
in laurel -- n = 1
in hardy -- n = 1    ;; NOTE DIFFERENCE -- here hardy is called from laurel 
in hardy -- n = 100  ;; here hardy is called from the main program 

Static Scoping with Nested Procedures


    begin
    integer m, n;

    procedure laurel(n: integer);
        begin

        procedure hardy;
            begin
            print("in hardy -- n = ", n);
            end;

        print("in laurel -- m = ", m);
        print("in laurel -- n = ", n);
        hardy;
        end;

    m := 50;
    n := 100;
    print("in main program -- n = ", n);
    laurel(1);
    /* can't call hardy from the main program any more */
    end;
The output is:
in main program -- n = 100
in laurel -- m = 50
in laurel -- n = 1
in hardy -- n = 1