|
|
Definitions:
meaning
| form | | | |
|
Definition = a syntactic construct
whose meaning is the establishment of a binding,
including possibly the creation of the bound-to memory object.
Elaboration.
"Algol 68 and Ada use the term elaboration to refer to the process
by which declarations become active when [encountered in the flow of control].
Elaboration entails the creation of bindings. In many languages,
it also entails the allocation of stack space for local objects,
and possibly the assignment of initial values"
[PLP 116].
"If [a] subroutine [with local variable declarations]
is called repeatedly, each invocation is said to create and destroy
a separate instance of each local variable"
[PLP 110].
|
|
Compare the lifetime of the binding and the lifetime of what it is bound-to:
Eg. «Semantically, the lifetime of a local Fortran variable
(both the object itself and the name-to-object binding)
encompasses a single execution of the variable's subroutine.
Programmers can override this rule by using an explicit save
statement. A save-ed variable has a lifetime that
encompasses the entire execution of the program.
Instead of a logically separate object for every invocation of a subroutine,
the save statement arranges for a single object
that retains its value from one invocation of the subroutine to the next.
(The name-to-variable binding, of course, is inactive when the subroutine
is not executing, because the name is out of scope.) »
[PLP 117].
In parameter passing by reference,
the binding between formal parameter (NAME)
and variable (MEMORY OBJECT) is destroyed at return time,
but the passed variable (and maybe other bindings for it) still exists.
[PLP 109].
We talk of a dangling [linguistic] reference
if a binding exists but binds the name to a MEMORY OBJECT that has been destroyed
[PLP 109].
| | | |
|
|
|
|
2. Bindings are not active everywhere/all-the-time
|
«At any given point in a program's execution, the set of active bindings
is called the current referencing environment » [PLP 116].
NB: Not active is not the same as destroyed (end of lifetime):
For example, «[b]indings to variables declared in a module
are inactive outside the module, not destroyed »
[PLP 123].
|
|
|
|
|
Scope. «The textual region of the program in which a binding is active is its scope »
[PLP 115].
The scope of a binding (not the binding itself)
is determined by static or dynamic scope rules
under the influence of declarations.
The scope of a binding can have "holes",
in which the binding is invisible (in the referencing environment),
usually because it is hidden by (the scope of) another binding for the same name.
«Some languages allow the programmer to access the outer meaning of a name
by applying a qualifier or scope resolution operator »
[PLP 121].
«In addition to talking about the "scope of a binding," we sometimes
use the word scope as a noun all by itself, without a specific binding in mind.
Informally, a scope is a program region of maximal size in which no bindings
change (or at least none are destroyed) »
[PLP 116].
«Modules into which [non-predefined] names must be explicitly imported
are said to be closed scopes. By extension,
scopes that do not require imports are said to be open scopes.
Modules are closed in Modula (1, 2, and 3) but open in Ada.
Nested subroutines are open scopes in most Algol families.
Important exceptions are Euclid, in which both modules and subroutine scopes are closed,
Turing and Modula (1), in which subroutines are optionally closed,
and Clu, which outlaws the use of nonlocal variables entirely
[but not nonlocal constants and subroutines]. ...
Import lists serve to document the program:
the use of names from surrounding scopes is really part of the
interface between a subroutine and the rest of the program »
[PLP 125].
|
|
| | | |
|
|
|
| PL Design Decision: Your choice of scope rules
|
(a) Static scoping.
«In a language with static (lexical) scoping,
the bindings between names and [memory] objects
can be determined at compile time by examining the text of the program,
without consideration of the flow of control at run time »
[PLP 116].
«Algol-style nesting [of blocks with local declarations]
gives rise to the closest nested scope rule for resolving
bindings from names to objects: a name that is introduced in a declaration
is known in the scope in which it is declared, and in each internally
nested scope, unless it is hidden by another declaration
of the same name in one or more nested scopes.
To find the object referenced by a given use of a name,
we look for a declration with that name in the current, innermost scope.
If there is one, it defines the active binding of the name.
Otherwise, we look for a declaration in the immediately surrounding scope.
We continue outward ... until we reach the outer nesting loevel of the program,
where global objects are declared. If no declaration is found at any level,
then the program is in error.
... It is common to consider [the language's built-in or predefined objects]
to be declared in an extra, invisible, outermost scope, which surrounds the scope
in which global objects are declared »
[PLP 118].
|
|
(b) Dynamic scoping.
«In a language with dynamic scoping, the bindings between names and
objects depend on the flow of control at run time, and in particular
on the order in which subroutines are called ... the "current"
binding for a given name is the one encountered most recently
during execution and not yet destroyed by returning from its scope »
[PLP 129].
«It is not entriely clear whether the use of dynamic scoping
in Lisp and other early interpreted languages was delibereate or accidental.
... The modern consensus seems to be that dynaic scoping is usually a bad idea
... The principal argument in favor of dynamic scoping
is that it facilitates the customization of subroutines. »
[PLP 131].
|
|
| | | |
|
|
|
|
The choice influences what semantic object are defined
by nested procedure definitions with access to the names from the surrounding subprogram.
Static scoping requires this to be a closure:
|
|
| Closure
| |
A closure is a subroutine bundled together with a referencing environment.
The deep binding rule for first-class procedures is that
when a subroutine [name] is used as a value (a reference to the subroutine is created),
then a closure is created by associating it
with (a copy of) the current referencing environment
[PLP 142].
|
| | | |
|
|
|
Static scoping design choice: Scope of binding = block.
«Pascal specifies that the scope of a declaration
is the entire block in which it is declared,
including the space between the beginning of the block and
the declaration (but excluding any holes in the scope, of course) »
[PLP 150].
Modula-3 the same [PLP 151].
In Java, classes in a file can be used before their definition.
«In a similar vein, members of a Java or C++ class are visible
throughout the code of the member functions of the class,
regardless of the order in which the members are declared »
[PLP 151].
In combination with Pascal's (but not Modula-3's) declaration-before-use rule,
this may lead to additional error messages.
const missing = -1;
...
procedure foo;
const null = missing; (* error: foo.missing used before declared *)
missing = 0;
...
|
| |
Static scoping design choice: Forward reference
In Pascal, and similar in Modula-2,
types used to construct pointer types need to be in scope
(ie declared later in same block), but need not be declared before use
[PLP 151].
|
type Alink = ^A;
A = record next: Alink; ...
| |
| |
Static scoping design choice: Incomplete type forward declaration
In Ada, C and C++, incomplete type declarations allow forward declarations
of types defined later, so that they can be used before their definition.
Pascal allows forward declaration of routines.
[PLP 151]
|
type A;
type Alink is access A;
type A is record next: Alink; ...
procedure Q (); forward;
procedure P (); begin ... Q() ... end;
procedure Q (); begin ... P() ... end;
| |
|
|
|
|
|
|
|
|
|
|
|
| |