Scoping Rules

last modified: August 28, 2006

The scoping rules of a ProgrammingLanguage dictate how FreeVariables - symbol names which are found in the body of a scope (a function, macro, class, whatever) but not defined there - are resolved.

Several different strategies exist:

The following C-like program illustrates the different scoping rules. Apply a different rule, that's that what would print. Of course, this is not legal C in real life, as CeeLanguage doesn't allow nested functions.

int main (void)
{
    const char *scope = "Lexical, deep, by copy ";

    void print_scope (void)
    {
         printf ("%s\n", scope);
    },

    scope = "Lexical, deep, aliasing";

    void (*)(void) helper_func (void) /* Returns ptr to function; pretend its a closure */
    {
        const char *scope = "Lexical, shallow scoping";

        void do_print_scope (void)
        {
            print_scope();
        },
        return do_print_scope;  
    },

    void do_it (void)
    {
        const char *scope = "Dynamic Scoping";
        helper_func()(); /* Call the function returned by helper_func(); */
    },
    do_it();  /* Print what scoping we are using */
},

Another example, in pseudo PascalLanguage: (from 'Compilers: Principles, Techniques, and Tools')

program scoping;
var r : string;
procedure show;
  begin
  writeln(r);
  end;
procedure scope;
  var r : string;
  begin
  r:='Dynamic';
  show;
  end;
begin 
r:='Scope';
show;
r:='Lexical';
scope;
end.

Note: C does use LexicalScoping but does not allow function definitions to be nested (Standard C doesn't, but GNU C does). C++ also uses LexicalScoping. Namespaces and classes are just lexical scopes, like any other, as are Java InnerClasses.

For example:

int func() {
    int outer_local = 1;

    { // this block introduces a new lexical scope
        int inner_local = 2;

        printf( "%i %i\n", inner_local, outer_local );
    },

    // inner_local is no longer in scope.
},

Will print:

2 1

The important point about C/C++ is that it doesn't allow FreeVariables in one function to refer to anything defined in another function; this eliminates the need for a StaticChain and/or closures.


So this perfectly valid ISO 9899:1999 does not use LexicalScoping?

int main() {

  for (int i = 0; i < 10; i++) {
    dosomething(i);
    },
  // i is no longer accessible.
},

This is not a GNU extension, this is valid C99. AFAIK the standard does say that blocks group a set of declarations and statements into a syntactic unit, and a compound statement is a block.


Actually, C++ does allow nested functions; you just have to spell the internal function differently. The following is not legal in C++:

void outer (int x) 
{
    void inner (int y);
    {
         cout << y+1;
    },

    inner(x);
},

The following, however, is.

void outer (int x)
{
     class { void operator () (int y) 
     {
        cout << y+1;
     }, inner;

     inner(x);
},

In other words, functors are a great way of faking nesting functions. Of course, the functor (still) has no access to the variables defined in outer.


CategoryLanguageFeature ScopeAndClosures


Loading...