1

I am not sure if I understand correctly, why in older versions of Lisp there was not static scoping implemented, only dynamic one. Sussman and Guy L. Steele Jr. who have invented Scheme, have implemented only the static scoping into Scheme.

I find sometimes static variables more convenient to use, since they can be used as perfect state holders, although we should be careful to avoid undesired name collisions, as undesired side effect.

I know that static scoping is detected during compile time, while dynamic scoping only during the run time. And dynamic scoping is considered is difficult to dubug, and sometimes to reason about.

If we put above mentioned facts aside, I am not sure that I understand WHY is static scoping often considered better than, dynamic one?

jjpcondor
  • 1,386
  • 1
  • 19
  • 30

3 Answers3

6

The fundamental problem with dynamic scoping is that it is not compositional, and thereby violates abstraction. In particular, the behaviour of a piece of code (say, a function) generally depends on where it is called from, and what definitions are visible at the caller's site. Thus, a caller has to be careful not to define names that clash with (non-local) ones a callee uses. Consequently, the caller has to know the implementation details of every callee. That makes for terrible modularity. In particular, a change to the implementation of a function may break all callers.

Andreas Rossberg
  • 34,518
  • 3
  • 61
  • 72
3

Lexical scoping is better for the programmer because it enables them to reason better about their program. In particular, they can reason about a program from its source code (locally), not from its dynamic behavior.

Also, you can add a constrained form of dynamic scoping to a language using dynamic binding features like parameters. SRFI-39 is a general proposal for Scheme. Also see parameters in the Racket guide. This lets you get most of the benefits of dynamic scoping in a lexically scoped language (which is the better default).

Asumu Takikawa
  • 8,447
  • 1
  • 28
  • 43
3

Consider the following definition:

(define (make-adder n)
  (lambda (x) (+ x n)))

Now, when you call (make-adder 2), you get back a function. What does this function do? Let's have a look:

(let ((add2 (make-adder 2)))
  (let ((n 10))
    (add2 n)))
;=> ?

What will the above code evaluate to? It depends on the scoping rules:

  1. In a lexically-scoped Scheme, the result will be 12, since the n in the definition of make-adder is distinct from the n in the sample code.
  2. In a (hypothetical) dynamically-scoped Scheme, the result will be 20, since n has been rebound to 10 at the time + is called.

Now, both kinds of behavior follow simple, predictable rules. But note that in the lexically-scoped case, you can look at the definition of make-adder and are able to relate the reference to n to its declaration locally, without knowing about the context in which make-adder will be used. This is not true in the dynamically-scoped case. (In fact, the argument to make-adder is completely superfluous under dynamic scoping.)

Because of this, lexical scoping is an advantage when reasoning about the behavior of make-adder, which is why it is usually (but not always) preferred.

Matthias Benkard
  • 15,497
  • 4
  • 39
  • 47
  • Matthias, thank you for this eloquent example. Do you think, if there would-could exist some hypothetical situation where dynamically-scoped code would be far superior, than the lexically-scoped equivalent? – jjpcondor Aug 20 '12 at 16:42
  • 1
    @jjpcondor Yes, there are situations in which dynamic scoping is very useful. In Common Lisp, for example, which supports both lexical and dynamic variables, dynamic scoping is often used for context-sensitive settings. You can write something like `(let ((*print-base* 16)) (do-stuff))` and have all numeric output done by `(do-stuff)` be in base 16. Or you could rebind `*standard-output*` to point to a file, which redirects all output with no explicit destination in the corresponding dynamic scope into that file (somewhat like redirecting `stdout` via `>` in Unixoid operating systems). – Matthias Benkard Aug 20 '12 at 16:55