Skip to main content

Environments

If you haven't read my notes on environment diagrams, now is a good time to read those.

Parent Frames

With the exception of the global frame, every function's execution frame has a parent: the frame in which the function was created. When you call a function, the function's frame first looks for references within its frame. If it doesn't find one, it goes up a frame and keeps doing this until it hits the global frame. If it still doesn't find a reference to a specified variable or function, the variable or function doesn't exist.

This idea is crucial: a frame can only deal with variables in or above it, and a frame is only created upon execution of a function. This is also why a frame doesn't necessarily become irrelevant upon completion. Check out this demo. Here's the code, for convenience:

a = 1

def x(b):
    c = 3
    def y(d):
        e = 5
        return b + d + e
    return y

z = x(a + 1)
f = 6
z(4)

If you step through this code, you'll see that the global frame first contains a and x. When we try to assign z, we call x, creating a new frame. The first thing that happens is that every parameter gets evaluated and written into the new frame. In x, we write the value of b into the frame right off the bat. Then we add c and y to our frame. Notice that the function description of y contains [parent=f1]. This is important -- f1 is the frame we created for x, as it's now labeled. For the context of 61A, you'll always label your frames, even if it becomes irrelevant upon completion. Now, we return y, so x is done executing. Why doesn't it disappear?

Because there's a reference within the frame of x that we could use outside of it. As long as there are references pointing to anything inside that frame, we cannot get rid of it. There is now a z value in the global frame, and we proceed to create a new f variable. This is mostly to show that f1 sticks around.

A new frame is created when we call z (notice that it's a higher order function).

What a Frame Entails

Every frame contains variables and functions, and everything in a frame can refer to everything else in that frame. The idea behind having indiividual frames for every function execution is to make sure that a function only has access to what it needs. Giving it extraneous information could unnecessarily slow down the program, for example, so you'd want to find a way to just store the information you need.