Dynamic Binding - MIT/GNU Scheme 7.7.91
Description: MIT/GNU Scheme 7.7.91

Next: Definitions, Previous: Lexical Binding, Up: Special Forms

### 2.3 Dynamic Binding

— special form: fluid-let ((variable init) ...) expression expression ...

> The inits are evaluated in the current environment (in some unspecified order), the current values of the variables are saved, the results are assigned to the variables, the expressions are evaluated sequentially in the current environment, the variables are restored to their original values, and the value of the last expression is returned.

> The syntax of this special form is similar to that of `let`, but `fluid-let` temporarily rebinds existing variables. Unlike `let`, `fluid-let` creates no new bindings; instead it assigns the value of each init to the binding (determined by the rules of lexical scoping) of its corresponding variable.

> MIT/GNU Scheme allows any of the inits to be omitted, in which case the corresponding variables are temporarily unassigned.

> An error of type `condition-type:unbound-variable` is signalled if any of the variables are unbound. However, because `fluid-let` operates by means of side effects, it is valid for any variable to be unassigned when the form is entered. Here is an example showing the difference between `fluid-let` and `let`. First see how `let` affects the binding of a variable:

>               (define variable #t)
>               (define (access-variable) variable)
>               variable                                =>  #t
>               (let ((variable #f))
>                 (access-variable))                    =>  #t
>               variable                                =>  #t

> `access-variable` returns `#t` in this case because it is defined in an environment with `variable` bound to `#t`. `fluid-let`, on the other hand, temporarily reuses an existing variable:

>               variable                                =>  #t
>               (fluid-let ((variable #f))              ;reuses old binding
>                 (access-variable))                    =>  #f
>               variable                                =>  #t

> The extent of a dynamic binding is defined to be the time period during which the variable contains the new value. Normally this time period begins when the body is entered and ends when it is exited; on a sequential machine it is normally a contiguous time period. However, because Scheme has first-class continuations, it is possible to leave the body and then reenter it, as many times as desired. In this situation, the extent becomes non-contiguous.

> When the body is exited by invoking a continuation, the new value is saved, and the variable is set to the old value. Then, if the body is reentered by invoking a continuation, the old value is saved, and the variable is set to the new value. In addition, side effects to the variable that occur both inside and outside of body are preserved, even if continuations are used to jump in and out of body repeatedly.

Here is a complicated example that shows the interaction between dynamic binding and continuations:

         (define (complicated-dynamic-binding)
           (let ((variable 1)
                 (inside-continuation))
             (write-line variable)
             (call-with-current-continuation
              (lambda (outside-continuation)
                (fluid-let ((variable 2))
                  (write-line variable)
                  (set! variable 3)
                  (call-with-current-continuation
                   (lambda (k)
                     (set! inside-continuation k)
                     (outside-continuation #t)))
                  (write-line variable)
                  (set! inside-continuation #f))))
             (write-line variable)
             (if inside-continuation
                 (begin
                   (set! variable 4)
                   (inside-continuation #f)))))

Evaluating (complicated-dynamic-binding) writes the following on the console:

         1
         2
         1
         3
         4

Commentary: the first two values written are the initial binding of `variable` and its new binding after the `fluid-let`'s body is entered. Immediately after they are written, `variable` is set to 3, and then `outside-continuation` is invoked, causing us to exit the body. At this point, 1 is written, demonstrating that the original value of `variable` has been restored, because we have left the body. Then we set `variable` to 4 and reenter the body by invoking `inside-continuation`. At this point, 3 is written, indicating that the side effect that previously occurred within the body has been preserved. Finally, we exit body normally, and write 4, demonstrating that the side effect that occurred outside of the body was also preserved.