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