Shadowing (ANSI and GNU Common Lisp Document)

Next: Extent, Previous: Closures and Lexical Binding, Up: Evaluation

#### 3.1.5 Shadowing

If two forms that establish lexical bindings with the same name N are textually nested, then references to N within the inner form refer to the binding established by the inner form; the inner binding for N shadows the outer binding for N. Outside the inner form but inside the outer one, references to N refer to the binding established by the outer form. For example:

     (defun test (x z)
       (let ((z (* x 2)))
         (print z))
       z)

The binding of the variable `z` by let shadows the parameter binding for the function `test`. The reference to the variable `z` in the print form refers to the let binding. The reference to `z` at the end of the function `test` refers to the parameter named `z`.

Constructs that are lexically scoped act as if new names were generated for each object on each execution. Therefore, dynamic shadowing cannot occur. For example:

     (defun contorted-example (f g x)
       (if (= x 0)
           (funcall f)
           (block here
              (+ 5 (contorted-example g
                                      #'(lambda () (return-from here 4))
                                      (- x 1))))))

Consider the call `(contorted-example nil nil 2)`. This produces `4`. During the course of execution, there are three calls to `contorted-example`, interleaved with two blocks:

     (contorted-example nil nil 2)
       (block here_1 ...)
         (contorted-example nil #'(lambda () (return-from here_1 4)) 1)
           (block here_2 ...)
             (contorted-example #'(lambda () (return-from here_1 4))
                                #'(lambda () (return-from here_2 4))
                                0)
                 (funcall f)
                        where f ⇒  #'(lambda () (return-from here_1 4))
                     (return-from here_1 4)

At the time the `funcall` is executed there are two block exit points outstanding, each apparently named `here`. The return-from form executed as a result of the `funcall` operation refers to the outer outstanding exit point (here_1), not the inner one (here_2). It refers to that exit point textually visible at the point of execution of function (here abbreviated by the `#'` syntax) that resulted in creation of the function object actually invoked by funcall.

If, in this example, one were to change the `(funcall f)` to `(funcall g)`, then the value of the call `(contorted-example nil nil 2)` would be `9`. The value would change because funcall would cause the execution of `(return-from here_2 4)`, thereby causing a return from the inner exit point (here_2). When that occurs, the value `4` is returned from the middle invocation of `contorted-example`, `5` is added to that to get `9`, and that value is returned from the outer block and the outermost call to `contorted-example`. The point is that the choice of exit point returned from has nothing to do with its being innermost or outermost; rather, it depends on the lexical environment that is packaged up with a lambda expression when function is executed.

Next: Extent, Previous: Closures and Lexical Binding, Up: Evaluation