Subject: Re: defvar affecting captured closure variables ?
From: rpw3@rpw3.org (Rob Warnock)
Date: Mon, 08 Oct 2007 02:55:59 -0500
Newsgroups: comp.lang.lisp
Message-ID: <NbudnTvbLv4Sf5TanZ2dnUVZ_judnZ2d@speakeasy.net>
Eli Bendersky  <eliben@gmail.com> wrote:
+---------------
| > [1] My current version:
| >
| > (defmacro deflex (var val &optional (doc nil docp))
...[trimmed]...
| 
| Rob, this looks interesting. Can I consider it as a viable replacement
| for defparameter at the top level for defining lexical globals ?
+---------------

I certainly use it that way quite liberally in my own code,
especially for variables that are going to be set or referenced
at the REPL.

But I also still use DEFPARAMETER (with traditional *earmuffs*
on the variable) for variables that are ever going to be dynamically
rebound, since DEFLEX is *NOT* compatible with the DEFVAR/SHADOWABLE
approach[1] mentioned elsewhere in this thread. That is, if you do
(DEFVAR/SHADOWABLE FOO 13) or (DEFINE-SYMBOL-MACRO FOO (SYMBOL-VALUE 'FOO)),
then you can both LET-bind FOO lexically *and* reference the global
value using (LOCALLY (DECLARE (SPECIAL FOO)) FOO), e.g.:

    > (defvar/shadowable foo 13)

    FOO
    > (defun foo () foo)

    FOO
    > (let ((foo 27))
	(locally (declare (special foo)) (setf foo 53))
	(list foo (foo) (locally (declare (special foo)) foo)))

    (27 53 53)
    > foo

    53
    > (locally (declare (special foo)) foo)

    53
    > 

But if you (DEFLEX FOO 13), then (LOCALLY (DECLARE (SPECIAL FOO)) FOO)
is going to get the value cell for the symbol FOO itself, *not*
the global value of the backing variable for FOO. This can lead
to considerable confusion:

    > (deflex foo 13)

    FOO
    > (defun foo () foo)

    FOO
    > (let ((foo 27))
	(locally (declare (special foo)) (setf foo 53))
	(list foo (foo) (locally (declare (special foo)) foo)))

    (27 13 53)
    > foo

    13
    > (locally (declare (special foo)) foo)

    53
    > 

+---------------
| Is it portable across all implementation ?
+---------------

As far as I know, yes, it should be. It uses only ANSI CL constructs.

However, be aware that in CMUCL-19d and earlier there was a bug
in macro expansion that in some cases [e.g., "INCF FOO", but not
just "FOO" or "SETF FOO"] caused references to symbol macros that
had been shadowed by lexical variables to expand to the symbol macro
expansion instead of refering to the lexical variable. [This would
affect all symbol macros, including both DEFLEX and DEFVAR/SHADOWABLE.]
This bug was fixed in the CVS for "code/eval.lisp" as of Revision
1.43 2006-12-19, but to my knowledge there is not yet an official
"cmucl-19d-patch-NNN" for this. I posted a patch here in article
<URL:news:Y_Cdnbvi_4Ir4RvYnZ2dnUVZ_tunnZ2d@speakeasy.net> on 2006-12-18
[which also works in CMUCL-19c], or you can just extract the
routine MACROEXPAND-1 from the CVS tree version of "eval.lisp" at
<http://common-lisp.net/cgi-bin/viewcvs.cgi/*checkout*/src/
code/eval.lisp?rev=1.43&root=cmucl>.


-Rob

[1] In case you missed it, I was proposing this if one wanted
to use the "shadowable global special" approach:

    (defmacro defvar/shadowable (var &optional value (doc nil docp))
      `(progn
	 (setf (symbol-value ',var) ,value)
	 ,@(when docp
	     (list `(setf (documentation ',var 'variable) ,doc)))
	 (define-symbol-macro ,var (symbol-value ',var))))

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607