Title: II. Frames and frame structures
1- II. Frames and frame structures
- Frame set of bindings generated together
in a binding generation event (frame
mini environment ) - When an event generates frame F, then the new
environment is (for some E) - E itself was similarly generated
- In the future, E may become again the current
environment - Frames are added/removed in LIFO
- A stack discipline
2- Environment structure --- past and present frames
-- a tree each path from root is a stack
of frames - Activation start (binding generation event)
- generation of frame
- implemented as push (onto
current environment) - Look-up --- search in frame stack, top-to-bottom
- Activation exit -- restoration of previous
environment - Frame disposed of (automatically/garbage
collection) --- pop -
- Let us re-visit previous example
3- Example
- (start with empty environment)
- Activation directly evaluated
frame - The value 7 is returned, down to to act0
4Dynamic scoping
- Results of resolutions depend on how environments
are modified when a activation is entered -
- Option A new generated bindings are always
merged into current environment (at point of
entrance) - dynamic scoping
- Simple, elegant approach
- Works well with stack-based implementations of
pls - We discuss implementation, present examples ,
show that approach is
WRONG
5 6- Activation and frame stacks are in 1-1
correspondence! - Each activation A --- associated frame F(A)
generated removed together - Look-up when A is current (top of activation
stack) - starts at F(A) (then top of frame stack)
then (if needed) goes down - Wlog going down uses the dynamic parent to
reach the activation below, then its frame - Look-up follows the dynamic parents chain, until
a binding is found (or fail announced)
7- Example revisited (let x 3, f .)
- Act frame d-eval exp
evaluated exp -
- The result 7 is returned from 3 to 2 to 1 to
0 - Q What would happen if the body of f contained
f?
8- Example
- We start from g(3), after the bindings of the
let were established, showing successive
(partial) stacks, (control shown with a circle)
) - Here, f, y are d-evaluated
9- When returns with 4, we are
back at act(g) - Now, d-eval f, y1
- Finally, back in act(g), 45 evaluates 9, and
the computation of the let returns this
value
10See details of stack evolution next page
11Act frame eval
d-eval
The final result, 10, moves down to 0
12 13Act frame eval
d-eval
Wrong!
The final result is 9
14- The source of the problem A delay between
- creation of a function value (from a function
expression) - its application
- ? The bindings for its free variables available
when it is applied may differ from those when it
is created
15Act frame
d-eval
2 and the binding x?1 are gone! 3 is on top of
1
Free variable x (or worse, could be defined)
16- The source of the problem A delay between
- creation of a function value (from a function
expression) - its application
- ? The bindings for its free variables available
when it is applied may differ from those when it
is created
17What is the result? Right or wrong?
18What happens after a call E(2)?
19- Can such phenomena also happen in
C? -
20- In dynamic scoping the free (global) variables in
a function body are associated with bindings
late when resolution is performed - The associations use the stack of frames,
accessed in order of generation - This allows interference!
- ? no relationship to static
structure - Static structure is not a reliable predictor of
execution
21- Various problems of dynamic scoping
- Same calls of a function (with same arg value)
may return different results (including error
msgs in some) - (lack of referential transparency)
- Change of a formal parameter of a function may
cause others to change their behavior -
- A function called by F may see Fs parameters
and locals a breach of abstraction/security - Useless to perform static checks such as
- Static type-check
- Is a variable defined before being used? (free
var check)
unpredictable behavior, often unrelated to static
structure
22- Manifestation of problems does not require
- Higher-order functions
- Recursion
- (Although it is more common when these are
present) - Conclusion dynamic scoping is
- Simple, elegant, (quite) efficient, but wrong!
- now considered an error, not used in modern
pls - Recall
- Results of resolutions depend on how environments
are modified when a activation is entered - What other options are
there ?
23Static scoping
- The problem (in dynamic) A delay between
- creation of a function value and its application
- The bindings for its free variables available
when it is applied are different from those when
it is created - The solution
- When a function value is created, the bindings
for its free variables (from current environment)
are attached to it - When it is applied, these bindings are used as
base environment
24- A function value (static scoping) fv
ltpbEgt , where - p is the parameter(s)
- b is the body
- E is an environment with bindings for
- The triple ltpb,Egt is called a
- (function)
closure - Intended to be used later in various places
- (delayed evaluation)
- A closed package that contains everything
needed for its future evaluation(s)
25- Closure and environment creation
- When a function expression is evaluated in
environment E, the value ltparsb,Egt is created
- E is derived from E
- When a function value ltparsb,Egt is applied to
args in environment E - a frame F of bindings pars?args is generated
- the activation executes in environment
- When it terminates, the environment E is
restored
The environment component of a function value
is derived from that of its time place of
creation
26- Note environment creation upon entrance to let,
let is unchanged - For letrec --- below
27- Implementation of Environment creation
- (in all implementations, the term function
closure is used) - Fully computed at the time of creation
- The environment component of a function value is
computed (when it is created) by copying the
relevant bindings from the current environment - if E is current environment,
- That of an activation is computed (before it
starts) - A common choice in implementations of functional
pls
28- Using frames linked by references
- (A common approach for imperative pls)
- An environment is a (linked) list of frames,
viewed as a stack - An entry a frame a reference to the next
entry - F1,F2 F2, F3 ..
- The first entry in the list is the top of the
stack - The reference in an entry is its
- static parent or static pointer
29- An activation contain a reference to the
top/first entry of its environment - and a dynamic parent/pointer, to the next entry
on the activation stack - The dynamic and static parents, from an
activation and its environment, may lead to
unrelated activation and environment!
activations environments
env(a8) f8, f4, f1,
f11
a8
f8
f4
f1
a1
30- A function value ltpbFgt , where F is a
reference to a frame --- the top frame of the
current environment at its time of creation
- The triple ltpbFgt is also called a function
closure - (note it may contain extra bindings!)
- 4. implemented as push ---
create an entry lt F,top(E)gt , make it the new
top - (this reference is the static parent of
F)
Previous examples revisited
31A5 xy
A4 f, x5
Result 10 passed down to A4, A0
A0 3
F0 nill
32A4 xy
A3 g, 3
A2 is now gone from stack Frame lives!
A2
A1 f, 1
33A5 xy
Result 10 to A4 to A3 what next?
A4 f, x5
A3 g, 2
A0 3
F0 nill
34- Observations
- Assume (AF) are current
- static parent(F), dynamic
parent(A) - are not necessarily associated with each
other - When an activation dies, the frames of its
associated environment may be referenced from
- live activations or function
values - ? 1. An activation popped from stack is gone
(dead) - its associated frame (often) lives
on (where?) - 2. Static parent may correspond to no
live activation! - (is that a problem?)
35-
- The environment structure is a tree
- (how do we know it is a tree, not
a graph? ) - Current environment is a path from a node to the
root - When an activation starts, a node is added to the
tree, as a child of some existing node ( becomes
top of current environment) - When an activation terminates, a different path
becomes the current environment - Nodes are removed from the tree only by garbage
collection (when provably they are not
referenced from any live entity) - no explicit pop
-
36- Other kinds of blocks
- A function value is a package, carrying its own
environment, since it moves around and may be
invoked in various places - A regular block (let, let, letrec) has no need
of such a mechanism - Upon entrance to new region, new bindings are
added to current environment - (static parent dynamic parent!)
- Upon exit, previous environment is restored
- let and let are simple, letrec requires
re-consideration
37- Rules for let (entered in current environment
E) - Evaluate defining expressions in current
environment - Create the frame F for the defined variables
- Evaluate the body ( activation) in
- Upon exit, restore E
- reflects the scope rule of let, the fact that it
is not recursive - What are the rules for let?
38- For a letrec, the defining expressions need to
be evaluated in the new environment! - ? Assume
- is evaluated in environment E
-
- But, this solution does not work now!
39- The solution
- Do the evaluation of the functions and the
construction of the new environment in one step - The requirement
- After this step
40A solution with assignable cells (the Scheme
implementation)
What is the role of delayed evaluation here? Can
you think of a purely functional solution?
41- Assume computation starts from
- activation A0, and frame F0nill
- How will the activation stack and the environment
structure evolve? - Note The final value true is returned from final
activation i to i-1, to 0. Those in middle
just pass it on
42 43 44- Comments
- How does a computation start?
- A zeroth activation, with initial environment
which may be empty, or not (depending on
pl/implementation) - The model as described can explain
- activations and binding management
- in most languages, including
- interactive mode in functional
languages - however, the global environment and define in
Scheme behave differently (still based on
environments)
45- Functions in a pl exist on three levels
- L1 Function expressions (static)
- L2 function values (dynamic)
- L3 activations of function values
(dynamic) - The relationships L1??L2 , L2??L3 are 1-m
- Many values may be created from an expression
- Many activations of a value may occur, even be
live simultaneously - The distinction between L1, L2 is not evident in
substitution model and in dynamic scope
46- Is behavior under static scoping compatible
with static structure? - Denote
- For a use u(x) in program declu(u(x)) the
declaration d(x) that statically binds it
(static) - For a binding b generated at run-time for a
declaration d(x) declb(b)d(x) (dynamic) - For a use u(x) resol(u(x)) the binding
returned by resolving it in current environment
(dynamic) - Claim1 declb(resol(u(x)))
declu(u(x))
47- Meaning of arrows
resolves to - static binding
generated for
x?v1
d(x)
x?v2
d(x)
x?v3
x?v4
u(x)
u(x)
48- Can prove a stronger statement
- If a binding x?v is generated for declaration of
x for a new activation, - Then for every use of x in the scope of this
declaration, its resolution always returns v - let f
- let x 3 in lambda y.xy
- .
- f 5 returns 8 (always)
- Static structure is a reliable predictor of
execution
49- Static scope avoids the problems of dynamic
scope - Calls of a function with same arguments behave
the same referential transparency
holds - Change of formal parameter of a function does
not change behavior (in activations of other
functions) -- no
surprises - function is a black box no external function
may observe values of locals - Useful to perform static check
- that a use is in scope of a declaration
- guarantees resolution never returns
unbound variable - Static type-checking guarantees absence of
run-time type errors