behavior of `symbol-value` in `progv`

Viewed 77

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.

1 Answers

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.

Related