Subject: Re: large hashtable crashes SBCL and GCL
From: rpw3@rpw3.org (Rob Warnock)
Date: Thu, 21 Aug 2008 10:10:37 -0500
Newsgroups: comp.lang.lisp
Message-ID: <K4idnUgy9ofwGDDVnZ2dnUVZ_v3inZ2d@speakeasy.net>
<Mirko.Vukovic@gmail.com> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) wrote:
| > Richard J. Fateman <fate...@eecs.berkeley.edu> wrote:
| > +---------------
| > | The reason I had no *earmuffs* is that I was typing x and y in
| > | repeatedly for tests, and didn't want to type *x* and *y* so much.
| > +---------------
| >
| > Use DEFLEX to get (well, simulate) top-level lexical variables:
| >    http://rpw3.org/hacks/lisp/deflex.lisp
...
| Rob, this is really nitpicking, (and possibly wrong), but I am
| wondering if in your deflex gem one could do
| 
| CL-USER> (defmacro deflex2 (var val &optional (doc nil docp))
|   (let* ((s0 (symbol-name '#:*storage-for-deflex-var-))
| 	 (s1 (symbol-name var))
| 	 (s2 (symbol-name '#:*))
| 	 (s3 (symbol-package var))	; BUGFIX [see above]
| 	 (backing-var (intern (concatenate 'string s0 s1 s2) s3)))
|     `(prog2
| 	 (defparameter ,backing-var ,val ,(when docp `,doc))
| 	 (define-symbol-macro ,var ,backing-var)
|         ,(when docp
| 		 `(setf (documentation ',var 'variable) ,doc)))))
| 
| My only problem (i.e. lack of macro expertise) with this is that the
| when forms instead of returning nothing place a NIL in the macro
| expansion.  But that does not seem to hurt things.
+---------------

The idea of pushing the IF into the body of the PROGN is certainly
reasonable, and I've done it both ways at various times, but I left
the IF outside in the <http://rpw3.org/hacks/lisp/deflex.lisp> version
because I thought it would be a bit clearer to the newcomer.

However, since you brought it up...  ;-}  ;-}

First, my plain ,DOC gives identical results as your ,(WHEN DOCP `,DOC)
in the DEFPARAMETER's third arg. And neither solves the problem of the
third arg being always provided regardless of the value of DOC.[1]
Fixing that requires using the same splicing hack used below for
the (SETF (DOCUMENTATION ...)) clause.

Anyway, to the main point: if I were to push the IF down in the PROGN,
I would do it the following way instead, which uses a bit more magic
macro syntax but doesn't require the out-of-order thinking that your PROG2
introduced (and also doesn't leave orphan NILs anywhere in the code):

    (defmacro deflex (var val &optional (doc nil docp))    
      (let* ((s0 (symbol-name '#:*storage-for-deflex-var-))
	     (s1 (symbol-name var))
	     (s2 (symbol-name '#:*))
	     (s3 (symbol-package var))
	     (backing-var (intern (concatenate 'string s0 s1 s2) s3)))
	`(progn
	   (defparameter ,backing-var ,val ,@(when doc (list doc)))
	   ,@(when docp
	       (list `(setf (documentation ',var 'variable) ,doc)))
	   ;; Must be last, so the value of the form is the symbol VAR.
	   (define-symbol-macro ,var ,backing-var))))

Yes, this version is *slightly* more compact than my original, but
also perhaps a bit harder to figure out.

Note that this splicing trick is quite useful for both optional and
keyword parameters. But you *must* use the LIST and not just QUOTE
the optional value, that is, write ,@(WHEN DOC (LIST DOC)) and not
just ,@(WHEN DOC '(DOC)), since the latter can result in constant
structure being modified, which is a big no-no. Whereas LIST will
allocate a fresh cons that can be cheerfully spliced.

Back to you...


-Rob

[1] For maximum portability one should probably use the splicing hack
    on the third arg of DEFPARAMETER, too, since the CLHS defines that arg
    to be "a string", *not* "a string or NIL". Fortunately, this doesn't
    seem to matter in all the CLs I have access to -- (DEFPARAMETER FOO val)
    gives the same result as (DEFPARAMETER FOO val NIL). But I included that fix in the above
    version, too.

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