It is important to remember the meaning of static and dynamic scoping: The declarations to which references are bound are determinable before or at run-time, respectively. The specifics of how those associations are made before or during runtime (e.g., the lexical structure of the program vis-à-vis the run-time call chain) can vary.
Lexical scoping is a more bounded method of resolving references to declarations than is dynamic scoping. The location of the declaration to which any reference to a lexically scoped variable is bound is limited to the nested blocks surrounding the block containing the reference. By comparison, the location of the declaration to which any reference to a dynamically scoped variable is bound is less restricted. Such a declaration can exist in any procedure in the program that has access to call the procedure containing the reference, and the procedures that have access to that one, and so on. This renders dynamic scoping more flexible—typical of any dynamic feature or concept—than static scoping. The rules governing which procedures a particular procedure can call are typically based on the program’s lexical layout. For instance, if a procedure g is nested within a procedure f, and a procedure y is nested within a procedure x, then f can call g and x can call y, but x cannot call g and f cannot call y. The process is more globally distributed through a program. Table 6.5 compares the advantages and disadvantages of static and dynamic scoping. We implement lexical and dynamic scoping in interpreters in Chapter 11.
Table 6.5 Advantages and Disadvantages of Static and Dynamic Scoping
Scoping | Advantages | Disadvantages |
---|---|---|
Static |
improved readability; easier program comprehension; predictability; type checking/validation |
larger scopes than necessary; can lead to several globals; can lead to all functions at the same level; harder to implement in languages with nested and first-class procedures |
Dynamic |
flexibility |
reduced readability; reduced reliability; type checking/validation; can be less efficient to implement; difficult to debug; no locality of access; no way to protect local variables; easier to implement in languages with nested and first-class procedures |
Exercise 6.8.1 Evaluate the following Scheme expression:
Exercise 6.8.2 Can the Scheme expression from Conceptual Exercise 6.8.1 be rewritten with only let*? Explain.
Exercise 6.8.3 Consider the following two C++ programs:
Does the reference to a on the right-hand side of the assignment operator on line 7 of the first program bind to the declaration of the global variable a on line 4? Similarly, does the reference to a on line 6 of the second program bind to the local variable a declared on line 5? Run these programs. What can you infer about how C++ addresses scope based on the outputs?
Exercise 6.8.4 Consider the Java expression . Determine where the scope of x begins. In other words, is the x on the right-hand side of the assignment from another scope or does it refer to the x being declared on the left-hand side? Alternatively, is this expression even valid in Java? Explain.
Exercise 6.8.5 Consider the following C program:
Using static scoping, the declaration of x in p (line 4) takes precedence over the global declaration of x (line 1) in the body of p. Thus, the global integer x cannot be accessed from within the procedure p. The global declaration of x has a scope hole inside of p.
In C++, can you access the x declared in line 1 from the body of p? If so, how?
Exercise 6.8.6 Recall that Scheme uses static scoping.
(a) Consider the following Scheme code:
What is the result of ?
(b) Consider the following Scheme code:
What is the result of (g ′(a b c))?
Exercise 6.8.7 Consider the following skeletal program written in a block-structured programming language:
(a) If this language uses static scoping, what is the type of the variable x printed on line 17 in procedure p3?
(b) If this language uses dynamic scoping, what is the type of the variable x printed on line 17 in procedure p3?
Exercise 6.8.8 Consider the following Scheme program:
(a) Annotate lines 5–7 of this program with comments indicating to which declaration of f on lines 1, 2, and 4 the references to f on lines 5–7 are bound.
(b) Annotate lines 1, 2, and 4 of this program with comments indicating, with line numbers, the scope of the declarations of f on lines 1, 2, and 4.
Exercise 6.8.9 In C++, is a variable declared in a for loop [e.g., ] visible after the loop terminates when not declared in an outer scope? How about those in other program blocks, such as if, while, or a block in general (i.e., created with { and })?
Exercise 6.8.10 Evaluate the Scheme expression in the last paragraph of Section 6.7 using lexical scoping.
Exercise 6.8.11 Explain the evaluation of the following Scheme code:
Exercise 6.8.12 Explain the evaluation of the following Scheme code:
Exercise 6.8.13 Can a programming language that uses dynamic scoping also use static type checking? Explain.
Exercise 6.8.14 Can a programming language that uses dynamic type checking also use static scoping? Explain.
Exercise 6.8.15 Consider the following Scheme expression:
Will this expression return 1 when evaluated under dynamic scoping, even in the absence of a letrec expression? Explain.
Exercise 6.8.16 Write a Scheme program that outputs different results when run using lexical scoping and dynamic scoping.
3.128.226.121