[pro] couple questions about dynamic bindings

Tobias C Rittweiler tcr at freebits.de
Thu Dec 30 12:32:55 UTC 2010


In article <4CBC918B-9B18-4C07-B289-A95040C33919 at gerg.org>,
 Greg Gilley <ggilley at gerg.org> wrote:

> There are some tests in the common-lisp test suite with dynamic binding that 
> I don't understand. If someone could help shed some light on them I'd 
> appreciate it.
> 
> progv makes it's arguments special. I don't understand how they can be a 
> different special than the one declared in the let. I'd love an explanation.
> 
> (let ((x 0))
>     (declare (special x))
>     (progv '(x) ()
>       (boundp 'x))) ==> NIL
> 
> (let ((x 0))
>     (declare (special x))
>     (progv '(x) () (setq x 1))
>     x) ==> 0
> 
> Thanks,
> 
>         Greg

Notice that PROGV does *not* make a binding special. If you
want to do that at run-time, you have to use

  (proclaim `(special ,name))

For illustration, consider the following case:

  CL-USER> (progv '(.x.) '(:progv)
              (let ((.x. :inner-let)) #'(lambda () .x.)))
  #<FUNCTION (LAMBDA ()) {CDA3DCD}>
  CL-USER> (let ((.x. :outer-let)) (funcall *))
  :INNER-LET

PROGV can /basically/ be thought of as being a macro
that expands to

  (let ((old-values (mapcar #'symbol-value <VARS>)))
    (unwind-protect
       (progn (mapc #'(setf symbol-value) <VALS> <VARS>)
         . <BODY>)
      (mapc #'(setf symbol-value) old-values <VARS>)))

It's more complicated than that but I think it suffices as
a mental model.

In case of multi-threading, its implementation is even more
complicated because it "must" be ensured that PROGV establishes
thread-local bindings. (The quotes around "must" because
multi-threading is, as you probably know, not part of the ANSI
standard.) 

Consider:

  CL-USER> (defparameter *foo* :global)
  *FOO*
  CL-USER> (sb-thread:make-thread #'(lambda ()
                                      (progv '(*foo*) '()
                                        (setq *foo* :thread))))
  #<SB-THREAD:THREAD RUNNING {CEEBFA9}>
  CL-USER> (sb-thread:join-thread *)
  :THREAD
  CL-USER> *foo*
  :GLOBAL

Regards,

  -T.





More information about the pro mailing list