Dynamic scoping
- This article or section should be merged with scope (programming).
Dynamic scoping is the policy of giving values to variables that have a well-defined extent in time (during execution) instead of in space (literal distance in the source code: this is lexical scoping). To make the result easier to understand, to make the association of multiple separate values with one variable well-defined, and for efficiency (see below), generally variable bindings are created in a LIFO manner: a binding outlives all bindings created during its lifetime, and a new binding hides all preexisting bindings for the same variable.
Generally certain blocks are defined to create bindings whose lifetime is the execution time of the block; this adds a hint of lexicality to the scoping. However, since a section of code can be called from many different locations and situations, it can be difficult to determine at the outset what bindings will apply when a variable is used. This can be beneficial; application of the principle of least knowledge suggests that code avoid depending on the reasons for (or circumstances of) a variable's value, but simply use the value according to the variable's definition. This narrow interpretation of shared data can provide a very flexible system for adapting the behavior of a function to the current state (or policy) of the system. However, this benefit relies on careful documentation of all variables used this way as well as on careful avoidance of assumptions about a variable's behavior, and does not provide any mechanism to detect interference between different parts of a program. As such, dynamic scoping can be dangerous and many modern languages do not use it. Some languages, like Perl and Common Lisp, allow the programmer to choose lexical or dynamic scoping when (re)defining a variable.
Example
The following example uses the syntax of C:
#include <stdio.h>
int x, y;
void a()
{
int product;
product = x * y;
printf("%d, ", product);
}
void b()
{
int y;
y = 5;
a(); /* 9 * 5 = 45 */
}
void main()
{
x = 9;
y = 4;
b();
a(); /* 9 * 4 = 36 */
}
Were C to use dynamic scoping, the value for y in b() would be in effect while b() called a(), and the output would be "45, 36"; in actuality b()'s assignment to y is to a different y (this is an instance of shadowing) and does not affect the global y, so the output is "36, 36".
Implementation
Dynamic scoping is extremely simple to implement. To find an identifier's value, the program traverses the runtime stack, checking each activation record (each function's stack frame) for a value for the identifier. This is known as deep binding. An alternate strategy that is usually more efficient is to maintain a stack of bindings for each identifier; the stack is modified whenver the variable is bound or unbound, and a variable's value is simply that of the top binding on the stack. This is called shallow binding. Note that both of these strategies assume a LIFO ordering to bindings for any one variable; in practice all bindings are so ordered.
Categories: Articles to be merged | Computer science