common-lispdynamic-variables

behavior of `symbol-value` in `progv`


Considering the behavior of dynamic and lexical bound variables, I understand the output of symbol-value in the following code (dynamically bound variable a is shadowed by a lexical bound variable a (that explanation is wrong, see edit below)):

(defvar a 1)
(let ((a 2))
  (list a (symbol-value 'a)))
 ; => (2 2)

But when using progv to create a similar environment, symbol-value gives a different result:

(progv '(x) '(1)
  (let ((x 2))
    (list x (symbol-value 'x))))
 ; => (2 1)

Why is (symbol-value 'x) returning 1 in the second example?

final edit accompanying the accepted answer: throughout comments at Rainer Joswig's answer I learnt that (let ((a 2)) ... ) does not bind a lexical variable, but shadows the value of the former dynamic binding. Also Martin Buchmann pointed out, in a comment, that symbol-value ignores lexical variables.


Solution

  • The PROGV special form creates dynamic bindings, but does not declare the variable to be special for enclosed forms.

    Thus we need to declare the LET binding of the variable x to be special:

    CL-USER 27 > (progv '(x) '(1)
                   (let ((x 2))
                     (declare (special x))
                     (list x (symbol-value 'x))))
    (2 2)
    

    DEFVAR OTOH declares its variable to be special. Globally and there is no direct way to undo that declaration.