Under static scoping, if all function values are created at compile-time, then identifiers can be discarded at run-time, because each use of an identifier can be compiled into a stack offset.
Dynamic scoping requires keeping knowledge of names at runtime. Names refer to values in the most recently entered scope, which can only be known at runtime.
Sometimes dynamic scoping is convenient. The behavior of a function can be changed without recompiling, just by calling it from inside an environment where global identifiers have different bindings.
However the same behavior can be obtained with static scoping and assignment:
Dynamic scoping makes programs harder to understand. The example above shows that assignment commands also make programs harder to understand.var s = 10.0;
function scale (x: real): real;
begin
return x*s;
end;procedure update (v: vector);
begin
var l: integer := length(v);
s := norm(v);
for j := 1 to l do scale(v[i])
end;
Dynamic scoping violates alpha-conversion: if the name s in the update procedure body was changed to t, under dynamic scoping a different effect is obtained.
The fundamental advantage of functional programming languages is that they are easier to understand, because they do not have the complexity of assignment commands.
If a program is easier to understand, it is also easier for a compiler to optimize.
For example the lifetime of s above is the execution of the whole program, while the local variable l has many lifetimes. Each lifetime of l is one execution of the body of update. Conceptually, update has new local variables at each call, which just happen to have the same name as previously existing variables.
Note that the executions of blocks are always strictly nested. They can't overlap, so the lifetimes of variables declared in blocks also cannot overlap.
If memory for a variable is allocated and deallocated explicitly by the programmer, then lifetimes can overlap. For example:
malloc(x);This example shows that heap-based variables are harder to understand (because they have more freedom) than variables declared in the regular way. regular variables are called stack variables because memory management for them can be done in a very simple way, with push and pop operations on a stack.
malloc(y);
free(x);
free(y);
The most common persistent variables are files. Pascal programs typically use what is called a persistent variable: the file named input.
Most languages have implementation-dependent restrictions on persistent variables. For example in Pascal a persistent variable must be of the type file of X for some component type X.
These limitations were to take account of implementation constraints,
but they are excessive. For example Pascal has no random-access files.
A variable with this behaviour is called a static variable in C, or called an own variable in Algol 60.
One important use for such a variable is to keep track of the seed used by a pseudo-random number generator:
Here, we do not want the variable seed to have a new lifetime each time prng is called, but we do want this variable to be visible only inside prng.function prng (): int;
static var seed : int = initialval;
begin
seed := update(seed);
return transform(seed);
end;