Subject: Re: defvar affecting captured closure variables ?
From: rpw3@rpw3.org (Rob Warnock)
Date: Sat, 06 Oct 2007 23:11:51 -0500
Newsgroups: comp.lang.lisp
Message-ID: <vq6dnQgg7OkawZXanZ2dnUVZ_tqtnZ2d@speakeasy.net>
Kent M Pitman  <pitman@nhplace.com> wrote:
+---------------
| Incidentally, ignore the advice about global lexicals.  For better or
| worse, I'm pretty sure all you want is this:
| 
|  (define-symbol-macro foo (symbol-value 'foo))
| 
| Don't forget to use explicit special bindings when you really mean to 
| bind these globals, since otherwise you'll get a lexical foo when you
| bind foo.
+---------------

For this reason, and also to avoid unbound-variable mistakes, e.g.:

    > (define-symbol-macro foo (symbol-value 'foo))

    FOO
    > foo

    Error in KERNEL::UNBOUND-SYMBOL-ERROR-HANDLER:  the variable FOO is unbound.
       [Condition of type UNBOUND-VARIABLE]
       ...

I would suggest providing/using some binding macro for such shadowable
specials to make it clear what's going on, something like this [feel
free to suggest a shorter yet still perspicuous name]:

    > (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))))
            
    DEFVAR/SHADOWABLE
    > (defvar/shadowable foo 13 "An example shadowable special")
    
    FOO
    > (defun foo ()
	"A function which gives the global value of FOO."
	foo)
    
    FOO
    > (let ((foo 27))
        (list foo (incf foo) foo
	      (foo) (locally (declare (special foo)) (incf foo)) (foo)))
               
    (27 28 28 13 14 14)
    > foo
    
    14
    > 

The "DEFVAR/..." part of the name will suggest that this variable
*is* still intended to be used as a special at least in some contexts
while the ".../SHADOWABLE" [or some shorter, less-awkward phrase?]
will reassure one that its binding is lexically shadowable.


-Rob

p.s. I happen to think that having documentation strings
"just work" is worth a little extra effort in one's macros:

    > (describe 'foo)

    FOO is an internal symbol in the COMMON-LISP-USER package.
    It is a symbol macro with expansion: (SYMBOL-VALUE 'FOO).
    Macro documentation:
      An example shadowable special
    Function: #<Interpreted Function FOO {48A64D41}>
    Function arguments:
      There are no arguments.
    Function documentation:
      A function which gives the global value of FOO.
    Its defined argument types are:
      NIL
    Its result type is:
      *
    Its definition is:
      (LAMBDA () (BLOCK FOO FOO))
    > 

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