Kent M Pitman <pitman@world.std.com> wrote:
+---------------
| Peter Seibel <peter@javamonkey.com> writes:
| > Are you saying it's never appropriate for macros to generate new names
| > based on other names.
|
| As a point of style, I think it's never appropriate for other-than-
| definition macros to do this, and moreover that it's probably not
| appropriate for anything to do this that doesn't allow you to override
| the choice of symbol.
|
| My style suggestion, not rule of law.
|
| > Isn't that what DEFSTRUCT does?
|
| It's a definition macro. Single point of control. After that you just
| use the name.
+---------------
So this use of it would be o.k., then?
(defmacro deflex (var val &optional (doc nil docp))
"Defines a top level (global) lexical VAR with initial value VAL,
which is assigned unconditionally as with DEFPARAMETER. If a DOC
string is provided, it is attached to both the name |VAR| and the
name *STORAGE-FOR-DEFLEX-VAR-|VAR|* as a documentation string of
kind 'VARIABLE. The new VAR will have lexical scope and thus may
be shadowed by LET bindings without affecting its global value."
(let* ((s0 (load-time-value (symbol-name '#:*storage-for-deflex-var-)))
(s1 (symbol-name var))
(p1 (symbol-package var))
(s2 (load-time-value (symbol-name '#:*)))
(backing-var (intern (concatenate 'string s0 s1 s2) p1)))
`(progn
(defparameter ,backing-var ,val ,@(when docp `(,doc)))
,@(when docp
`((setf (documentation ',var 'variable) ,doc)))
(define-symbol-macro ,var ,backing-var))))
Notes:
1. It got called DEFLEX rather than DEFLEXICAL because almost all of
my usage of it is typing directly into the REPL. (Fingers get tired...)
It uses DEFPARAMETER semantics rather than DEFVAR for the same reason,
that is, that's usually what you want when typing manually. [And it
also matches the behavior of Scheme's top-level lexicals. (*ducks!*)]
2. I didn't parameterize the backing variable's name because I wanted
the signature to match DEFVAR and DEFPARAMETER, specifically w.r.t.
doc strings, and I didn't know how to do that without requiring a
doc string if one wanted a non-default prefix (the &OPTIONAL versus
&KEY issue). So I just picked a long prefix that seemed unlikely to
ever conflict.
3. I specifically *did* intern the backing variable's symbol into the
same package as the defined variable, so one could do the following
without conflict:
> (deflex foo 27)
> (deflex bar::foo 13 "FOO in the BAR package")
> (list foo bar::foo)
(27 13)
> (apropos 'foo)
BAR::*STORAGE-FOR-DEFLEX-VAR-FOO* [special variable] value: 13
BAR::FOO [symbol macro]
*STORAGE-FOR-DEFLEX-VAR-FOO* [special variable] value: 27
FOO [symbol macro]
>
4. Thanks to the denizens comp.lang.lisp for many useful discussions
(and flames!) on the topic of globals lexicals, and for the suggestion
for the simple and efficient (albeit inelegant) "shadow" variable
approach used above. [Note: Like several others, I had previously used
a single global adjustable vector of shadow values, with complicated
compile-time allocation of indices so that symbol-macro FOO expanded into
something like (AREF *LEXICAL-STORE* (LOAD-TIME-VALUE {index-for-FOO})).
But the above is much simpler.]
-Rob
-----
Rob Warnock, PP-ASEL-IA <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607