Scoping Rules

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

EditText of this page (last edited August 28, 2006) or FindPage with title or text search