Reputation: 815
I just met an unusual situation in my common lisp code when I wanna test locally
and declare
:
(defvar test-out 2) ;; make a dynamic variable
;; function below just simply re-write from locally doc
(defun test (out)
(declare (special out))
(let ((out 1))
(print out) ;; => 1
(print (locally (declare (special out)) out)))) ;; => 2
;; when argument has same name as outside dynamic variable
(defun test1 (test-out)
(declare (special test-out))
(let ((test-out 1))
(print test-out) ;; => 1
(print (locally (declare (special test-out)) test-out)))) ;; => also 1
I know the right name of dynamic variable should be *test-out*
, but I thought it just for programmer to tell dynamic variable conveniently.
I am a bit confuse about test1
function, it looks like locally declare
do not point test-out
to dynamic variable outside.
Can anyone explain to me test1
function's behavior? Thanks
Update:
(defvar test-out-1 3)
, and call it like (test1 test-out-1)
, still get print out result 1
and 1
.test1
's argument name from test-out
to test-out1
, recompile test1
, and problem disappears, print out results are 1
and 2
when I call (test1 test-out)
.(defvar test-out 2)
to (defvar test-out-1 2)
(change dynamic variable name). Then recompile whole file (no dynamic variable called test-out
this time, and test1
argument's name is test-out
), problem disappears.(defvar test-out 2)
, and (test1 test-out)
. This time, it prints out right answers: 1
and 2
.test1
again, then run (test1 test-out)
, it prints out 1
and 1
again, problem appears again.If I guess right, when test1
compiling, for some reason, its arguments' name connect to dynamic variable test-out
. That's why I receiving wrong result when I even call with different value, however, problem is solved by itself when I recompile test1
with different argument name or clean dynamic variable test-out
before recompile test.
If so, I still do not understand why compile function will effect by dynamic variable in the environment.
Upvotes: 2
Views: 210
Reputation: 139241
DEFVAR
declares a variable to be special - that means they will use dynamic bindings when bound and access to such a variable will look for dynamic bindings. Globally and on all binding levels. For now and in the future.
From then on, ALL uses and bindings of that variable in new code will be declared special automatically. Even local LET bindings. On all levels. There is no way to declare it unspecial. Thus a local special declaration in your test1
function now is not needed, it already is declared special. Every use or binding of it, even without explicit declaration is now using dynamic binding.
That's also the reason why any DEFVAR
or DEFPARAMETER
variable should be written as *variablename*
, to prevent accidentally declaring all variables with the same name to be special.
Avoid:
(defvar x 10) ; here X is explicitly declared special
(defun foo (x) ; here X is implicitly declared special
(let ((x ...)) ; here X is implicitly declared special
...))
Do:
(defvar *x* 10) ; here *X* is declared special
(defun foo (x) ; here X is lexical
(let ((x ...)) ; here X is lexical
...))
Upvotes: 6