home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!mcsun!uknet!edcastle!aiai!jeff
- From: jeff@aiai.ed.ac.uk (Jeff Dalton)
- Newsgroups: comp.lang.lisp
- Subject: Re: static, a.k.a. eval-once
- Message-ID: <7412@skye.ed.ac.uk>
- Date: 1 Sep 92 14:08:35 GMT
- References: <7399@skye.ed.ac.uk> <17u2ikINNs6g@early-bird.think.com>
- Sender: news@aiai.ed.ac.uk
- Organization: AIAI, University of Edinburgh, Scotland
- Lines: 97
-
- In article <17u2ikINNs6g@early-bird.think.com> barmar@think.com (Barry Margolin) writes:
- >In article <7399@skye.ed.ac.uk> jeff@aiai.ed.ac.uk (Jeff Dalton) writes:
- >>About 4 years ago, I wrote an EVAL-ONCE macro. It appears, with
- >>an explanation below. It has been claimed that my macro isn't
- >>portable because the behavior of gensyms isn't sufficiently
- >>restricted when compile and load is involved. What I want to
- >>know is:
- >>
- >> 1. Is there a problem with using GENSYM this way?
- >
- >I think it should work. While the compiler has to arrange for all
- >references to a particular gensym within a binary file to be the object,
- >similarly named gensyms in different binary files should refer to different
- >instances.
- >
- >BTW, I assume you realize that V should be a gensym, i.e. it should be:
-
- Yes. I'm not sure how I could have missed that.
-
- >I think your version can be simplified a bit. The expansion doesn't need a
- >LET binding:
- >
- >(defmacro eval-once (form)
- > (let ((var (gensym)))
- > `(if (boundp ',var)
- > (symbol-value ',var)
- > (set ',var ,form))))
-
- Both this and the V problem were fixed in the "#+maybe" version:
-
- #+maybe
- (defmacro eval-once (form)
- (let ((v (gensym)))
- `(locally (declare (special ,v))
- (if (boundp ',v)
- ,v
- (setq ,v ,form)))))
-
- I suspect (it was years ago) that what happened was that I started
- with something like your version, modified it (carelessly) to get
- around a bug in KCL, and then wrote the "#+maybe" version w/o realizing
- that it fixed the bug involving V.
-
- The bug in KCL was that if a gensym appeared more than once _as data_
- (eg, as a quoted symbol in two different places), they would end up as
- separate symbols after a compile/load. (This bug has now been fixed,
- I believe.) However, the "#+maybe" has the problem that the uses
- of comma-V as a variable and as data have to line up, which wouldn't have
- worked then in KCL (I suspect).
-
- >This looks suspiciously like the stuff we were discussing a few months ago,
- >where you wanted the ability to have modifiable literals in your program.
- >If that were allowed, you could do:
- >
- >(defstruct eval-once
- > (done nil)
- > value)
- >
- >(defmacro eval-once (form)
- > (let ((struct (make-eval-once)))
- > `(if (eval-once-done ',struct)
- > (eval-once-value ',struct)
- > (setf (eval-once-done ',struct) t
- > (eval-once-value ',struct) ,form)))))
-
- Well, I do want to have _some_ way to do this EVAL-ONCE trick.
-
- You're right to suspect that this is connected to our earlier
- discussion. I first brought up the static/eval-once issue on one of
- the Common Lisp mailing lists shortly after I'd written my macro (ie,
- some years back). If I recall correctly, what was said then was that
- gensyms weren't reliable enough but that LOAD-TIME-VALUE might do it
- (somehow). So I've had it in mind to figure out, sooner or later,
- whether LOAD-TIME-VALUE did help. Various things remind me of this --
- such things as the discussion about modifying constants and (now) the
- public review of the dpANS. (The latter one works by making me try
- to remember the things I was going to raise during public review,
- which leads me to remember other things too.)
-
- Anyway, modifying a quoted structure looks like one way to do
- eval-once, and LOAD-TIME-VALUE looks like it might help either by
- giving you a modifiable object (that isn't quoted) at load time or by
- letting you modify a quoted object (because you use the 2nd argument
- to LOAD-TIME-VALUE to _say_ it's modifiable. So, using the struct
- you defined, we might try:
-
- (defmacro eval-once (form)
- (let ((v (gensym)))
- `(let ((,v (load-time-value (make-eval-once))))
- (if (eval-once-done ,v)
- (eval-once-value ,v)
- (setf (eval-once-done ,v) t
- (eval-once-value ,v) ,form)))))
-
- But that's not enough in interpreted code.
-
- -- jd
-