Subject: Re: Macros that build function names
From: rpw3@rpw3.org (Rob Warnock)
Date: Tue, 05 Aug 2003 05:19:21 -0500
Newsgroups: comp.lang.lisp
Message-ID: <NvednWDvaYM0GbKiXTWc-g@speakeasy.net>
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