Notes on Scoping

Scoping determines where variables get their values. Consider the following Scheme program:

((lambda (x) ((lambda (f) ((lambda (x) (f 10)) 5)) (lambda (y) (+ x y)))) 3)

What does this program evaluate to? The two reasonable answers
would be 13 or 15, depending upon which value of x (3 or 5) is used in
`(+ x y)`. For purposes of discussion, let's rename the two
uses of x as a parameter to x1 and x2:

((lambda (x1) ((lambda (f) ((lambda (x2) (f 10)) 5)) (lambda (y) (+ x y)))) 3)

If x gets its value from x1, the value of this expression would be 13. If x gets its value from x2, the value would be 15. The issue is that x is used in (lambda (y) (+ x y)). Let's see how each could actually occur. First, how could x get 3 (the value of x1)?

((lambda (x1) ((lambda (f) ((lambda (x2) (f 10)) 5)) (lambda (y) (+ x y)))) 3) ==> ((lambda (f) ((lambda (x2) (f 10)) 5)) (lambda (y) (+ 3 y)))

The above example followed the law of substitution we have used all term. When we call (lambda (x1) ...) with 3, we replaced all x's in the scope of x1 with the 3. Continuing the evaluation would lead to an answer of 13.

Now let's see how we could get the answer 15:

((lambda (x1) ((lambda (f) ((lambda (x2) (f 10)) 5)) (lambda (y) (+ x y)))) 3) ==> [remember that x1 = 3] ((lambda (f) ((lambda (x2) (f 10)) 5)) (lambda (y) (+ x y))) ==> [remember that x1 = 3; f = (lambda (y) (+ x y)) ] ((lambda (x2) (f 10)) 5)) ==> [remember that x2 = 5; f = (lambda (y) (+ x y)); x1 = 3] (f 10) ==> [remember that x2 = 5; f = (lambda (y) (+ x y)); x1 = 3] ((lambda (y) (+ x y)) 10) ==> [remember that y = 10; x2 = 5; f = (lambda (y) (+ x y)); x1 = 3] (+ x y) ==> 15 (since x2 is the more "recent" than x1)

The first strategy is called *static scoping* because values
are determined statically (ie, not at run-time) from the program
text. The second strategy is called *dynamic scoping* because
values are determined at run-time.

We know from our work with Scheme to date that Scheme uses static scoping. History has taught that static scoping is far preferable to dynamic scoping because static scoping is more predictable. Under dynamic scoping, the programmer loses control over where a variable gets its value. For example, you could write a function that refered to x (but didn't have x as a parameter) and pass that function to code written by someone else. The value of x would be determined by how the other person's code used your function. Thus, you lose the ability to control, or even predict, what values x might receive.

Upshot: if you have to implement a language, use static scoping.

This page maintained by Kathi Fisler Department of Computer Science Worcester Polytechnic Institute |