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:

  1. 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