From: Francis Sergeraert
Subject: Re: Closure around defun
Date: 
Message-ID: <CL9GA3.GrA@imag.fr>
  The point is that your *print-length* is implicitly "special" because
declared in a 
(DEFVAR *PRINT-LENGTH* nil)
  at the initialization of Lisp.

  Do the following experience:

> (setf x 10)  ==>
10
> (let ((x 100))
    (defun bar () x))  ==>
BAR
> (bar)  ==>
100
> (defvar x)  ==>
X
> x  ==>
10
> (let ((x 100))
    (defun bar () x))  ==>
BAR
> (bar)  ==>
10
>

  Why these strange facts ? My personal model (is it right ??) is that
at  any  time you   have  the  global-environment-stack and  also  the
local-environment-stack.   When Lisp enters   a let,  it  adds the new
value, sorry the new binding in the official terminology, on the local
stack.  If a closure  is created, this local stack  is  keeped in this
closure. This was the case for the first definition of bar above.

  But if the  variable   is special, this    new binding, sorry   this
value..., is added on the global-environment. The local environment is
saved inside  a  created closure,  but it does   not  contain this new
value. Secondly when the  let is finished,  this new value  is removed
from the  global-environment.  This is  better showed in the following
extended examples.  Don't forget that evaluating  a symbol returns the
binding (local value) if  defined,  and on the  contrary (symbol-value
...) returns the global  one only and  the highest one if several have
been defined.

> (setf y 10)  ==>
10
> (let ((y 100))
    (print y)
    (print (symbol-value 'y))
    (defun bar () y))  ==>
100
10
BAR
> (bar)  ==>
100
> (defvar y)  ==>
Y
> y  ==>
10
> (let ((y 100))
    (print y)
    (print (symbol-value 'y))
    (defun bar () y))  ==>
100
100
BAR
> (bar)  ==>
10
>

Look also at this example:

> (let ((z 10))
    (declare (special z))
    (defun foo () z))  ==>
FOO
> (foo)  ==>
ERROR : z is unbound.

The value  of   z  is lost because   it  was  available only  on   the
global-stack and was not stored inside the closure.

And also:

> (let ((a 10))
    (declare (special a))
    (defun foo () (bar)))  ==>
FOO
> (let ((a 100))
    (defun bar () a))  ==>
BAR
> (foo)  ==>
100
>
 
because the a of the second let is pushed on the local-stack, therefore
keeped inside the definition of bar.

Personnally I regret  this model (or the right  one) is  not described
int the CLtLn; this would make much simpler the understanding of these
very esoteric notions of bindings vs values, extents vs scopes, etc.