From: Peter Seibel
Subject: eval-when needed?
Date: 
Message-ID: <m3u1ea96oj.fsf@localhost.localdomain>
So I'm back to trying to understand eval-when. I think I've mostly got
it but I just wanted to check one thing. Suppose I have a file that
defines a bunch of functions, variables (defvars), classes, etc. and
some macros that use them (calling the functions, stuffing bits of
data into the variables that will be used by the other macros during
their expansion, etc.)

A trivial (and silly) example of what I'm talking about is something
like this:

  (defpackage "SNIPPETS"
    (:use "COMMON-LISP")
    (:export "DEFSNIPPET" "DEFCODE"))

  (in-package "SNIPPETS")

  (defvar *snippets* (make-hash-table))

  (defmacro defsnippet (name &body snippet)
    `(eval-when (:compile-toplevel :load-toplevel :execute)
      (setf (gethash ',name *snippets*) ',@snippet)))

  (defmacro defcode (name &rest snippets)
    `(defun ,name ()
      ,@(mapcar #'(lambda (name) (gethash name *snippets*)) snippets)))


Which lets me do:

  [1] CL-USER(172): (use-package "SNIPPETS")
  T
  [1] CL-USER(173): (defsnippet one (format t "one"))
  (FORMAT T "one")
  [1] CL-USER(178): (defsnippet two (format t " two"))
  (FORMAT T " two")
  [1] CL-USER(179): (defcode foo one two)
  FOO
  [1] CL-USER(182): (foo)
  one two
  NIL
  [1] CL-USER(183): 


As in this example, the macros are not used in the file itself: they
are the public API. In this case, my understanding as that I don't
need to wrap anything (such as the defvar of *snippets*) in an
eval-when with :compile-toplevel because there's nothing that will be
needed at compile time *of this file*. Whereas if I actually used
defsnippet *in* this file, I'd need to use eval-when to make the
*snippets* variable exist when the macro is used during compilation of
this file.

Is that right?

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

  The intellectual level needed   for  system design is  in  general
  grossly  underestimated. I am  convinced  more than ever that this
  type of work is very difficult and that every effort to do it with
  other than the best people is doomed to either failure or moderate
  success at enormous expense. --Edsger Dijkstra

From: Kent M Pitman
Subject: Re: eval-when needed?
Date: 
Message-ID: <sfwof4i96ga.fsf@shell01.TheWorld.com>
Peter Seibel <·····@javamonkey.com> writes:

> As in this example, the macros are not used in the file itself: they
> are the public API. In this case, my understanding as that I don't
> need to wrap anything (such as the defvar of *snippets*) in an
> eval-when with :compile-toplevel because there's nothing that will be
> needed at compile time *of this file*. Whereas if I actually used
> defsnippet *in* this file, I'd need to use eval-when to make the
> *snippets* variable exist when the macro is used during compilation of
> this file.
> 
> Is that right?

Yes.
From: james anderson
Subject: Re: eval-when needed?
Date: 
Message-ID: <3E6D21F1.FA86B50B@setf.de>
Kent M Pitman wrote:
> 
> Peter Seibel <·····@javamonkey.com> writes:
> 
> > As in this example, the macros are not used in the file itself: they
> > are the public API. In this case, my understanding as that I don't
> > need to wrap anything (such as the defvar of *snippets*) in an
> > eval-when with :compile-toplevel because there's nothing that will be
> > needed at compile time *of this file*. Whereas if I actually used
> > defsnippet *in* this file, I'd need to use eval-when to make the
> > *snippets* variable exist when the macro is used during compilation of
> > this file.
> >
> > Is that right?
> 
> Yes.

there is also the case where a file may be compiled, but not immediately loaded.

"Whereas if [one] used defsnippet *in* [any code which gets compiled before] this file [gets loaded, one would] need to use eval-when to make the *snippets*
variable exist when the macro is used during compilation of [that code]."

?
From: Kent M Pitman
Subject: Re: eval-when needed?
Date: 
Message-ID: <sfwr89er80v.fsf@shell01.TheWorld.com>
james anderson <··············@setf.de> writes:

> Kent M Pitman wrote:
> > 
> > Peter Seibel <·····@javamonkey.com> writes:
> > 
> > > As in this example, the macros are not used in the file itself: they
> > > are the public API. In this case, my understanding as that I don't
> > > need to wrap anything (such as the defvar of *snippets*) in an
> > > eval-when with :compile-toplevel because there's nothing that will be
> > > needed at compile time *of this file*. Whereas if I actually used
> > > defsnippet *in* this file, I'd need to use eval-when to make the
> > > *snippets* variable exist when the macro is used during compilation of
> > > this file.
> > >
> > > Is that right?
> > 
> > Yes.
> 
> there is also the case where a file may be compiled, but not immediately loaded.

This is true, but I don't think this is a good reason to use eval-when.
This is a good reason to load the file.

If the file was already compiled, this stuff wouldn't have gotten done.
LOAD is how you say to make a file's contents active--not hoping that
COMPILE-FILE left stale data around.
From: james anderson
Subject: Re: eval-when needed?
Date: 
Message-ID: <3E6D429B.E330ADB3@setf.de>
Kent M Pitman wrote:
> 
> james anderson <··············@setf.de> writes:
> 
> > Kent M Pitman wrote:
> > >
> > > Peter Seibel <·····@javamonkey.com> writes:
> > >
> > > > As in this example, the macros are not used in the file itself: they
> > > > are the public API. In this case, my understanding as that I don't
> > > > need to wrap anything (such as the defvar of *snippets*) in an
> > > > eval-when with :compile-toplevel because there's nothing that will be
> > > > needed at compile time *of this file*. Whereas if I actually used
> > > > defsnippet *in* this file, I'd need to use eval-when to make the
> > > > *snippets* variable exist when the macro is used during compilation of
> > > > this file.
> > > >
> > > > Is that right?
> > >
> > > Yes.
> >
> > there is also the case where a file may be compiled, but not immediately loaded.
> 
> This is true, but I don't think this is a good reason to use eval-when.
> This is a good reason to load the file.
> 
> If the file was already compiled, this stuff wouldn't have gotten done.
> LOAD is how you say to make a file's contents active--not hoping that
> COMPILE-FILE left stale data around.

is the argument against build processes which compile "everything" before they load it implicit or explicit?

...
From: Kent M Pitman
Subject: Re: eval-when needed?
Date: 
Message-ID: <sfwk7f6zm8e.fsf@shell01.TheWorld.com>
james anderson <··············@setf.de> writes:

> Kent M Pitman wrote:
> > 
> > james anderson <··············@setf.de> writes:
> > 
> > > there is also the case where a file may be compiled, 
> > > but not immediately loaded.
> > 
> > This is true, but I don't think this is a good reason to use eval-when.
> > This is a good reason to load the file.
> > 
> > If the file was already compiled, this stuff wouldn't have gotten done.
> > LOAD is how you say to make a file's contents active--not hoping that
> > COMPILE-FILE left stale data around.
> 
> is the argument against build processes which compile "everything" 
> before they load it implicit or explicit?

If I understand your question:

I don't think such code is generally well-structured.
From: Kenny Tilton
Subject: Re: eval-when needed?
Date: 
Message-ID: <3E6D4813.2010709@nyc.rr.com>
james anderson wrote:
> 
> Kent M Pitman wrote:
> 
>>james anderson <··············@setf.de> writes:
>>
>>
>>>Kent M Pitman wrote:
>>>
>>>>Peter Seibel <·····@javamonkey.com> writes:
>>>>
>>>>
>>>>>As in this example, the macros are not used in the file itself: they
>>>>>are the public API. In this case, my understanding as that I don't
>>>>>need to wrap anything (such as the defvar of *snippets*) in an
>>>>>eval-when with :compile-toplevel because there's nothing that will be
>>>>>needed at compile time *of this file*. Whereas if I actually used
>>>>>defsnippet *in* this file, I'd need to use eval-when to make the
>>>>>*snippets* variable exist when the macro is used during compilation of
>>>>>this file.
>>>>>
>>>>>Is that right?
>>>>
>>>>Yes.
>>>
>>>there is also the case where a file may be compiled, but not immediately loaded.
>>
>>This is true, but I don't think this is a good reason to use eval-when.
>>This is a good reason to load the file.
>>
>>If the file was already compiled, this stuff wouldn't have gotten done.
>>LOAD is how you say to make a file's contents active--not hoping that
>>COMPILE-FILE left stale data around.
> 
> 
> is the argument against build processes which compile "everything" before they load it implicit or explicit?
> 

Implicit, as is the above argument against ever using macros.

-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Cells let us walk, talk, think, make love and realize
  the bath water is cold." -- Lorraine Lee Cudmore
From: Kent M Pitman
Subject: Re: eval-when needed?
Date: 
Message-ID: <sfwbs0ioats.fsf@shell01.TheWorld.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> james anderson wrote:
>
> > is the argument against build processes which compile "everything"
> > before they load it implicit or explicit?
> >
> 
> Implicit, as is the above argument against ever using macros.

Uh, can we say some things explicitly then?  I'd answer straightforwardly
worded straightforwardly.

I don't think there is a problem with defining macros and either using
their definitions in the same file (using eval-when where necessary to
boostrap things), though I prefer when I can to save the uses for a
different file than the definition.

I don't think there is a problem with using macros defined in another
file if you have loaded their definitions first.

Who made an argument against ever using macros? Certainly not me.

I think that build processes that compile everything before they load
it are fine, but those things better not have any macros in them.  If
they are compiling macros, they should stop and load the macros before
proceeding.  Macros are like extending the "language level".
Everything written using macros is in a new language that must be
loaded before it can be compiled or executed.

Relying on side-effects of compilation is the same as loading, but is
done by some backdoor kludge cheat way that tries to avoid a couple
of extra files at the expense of intelligibility of ordering.  It's
kind of the traditional Unix way, to enshrine an accident like that
and call it a feature, but it's not my personal favorite choice of how
to proceed.
From: Kenny Tilton
Subject: Re: eval-when needed?
Date: 
Message-ID: <3E6D5700.2000200@nyc.rr.com>
Kent M Pitman wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>james anderson wrote:
>>
>>
>>>is the argument against build processes which compile "everything"
>>>before they load it implicit or explicit?
>>>
>>
>>Implicit, as is the above argument against ever using macros.
> 
> 
> Uh, can we say some things explicitly then?  I'd answer straightforwardly
> worded straightforwardly.

But there goes all the fun of reading unintended things into others' 
writing!

> Who made an argument against ever using macros? Certainly not me.

James Anderson? My remark was aimed at his idea of a build mechanism 
which did not load as it compiled. Makes macros kinda unworkable. And, 
come to think of it, generic functions, since I have yet to sneak past 
the compiler a GF specialized on a class not yet defined.

Sorry for the "above" confusion.

-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Cells let us walk, talk, think, make love and realize
  the bath water is cold." -- Lorraine Lee Cudmore
From: james anderson
Subject: Re: eval-when needed?
Date: 
Message-ID: <3E6D5ACC.B28F8831@setf.de>
Kent M Pitman wrote:
> 
> ...
> 
> I don't think there is a problem with using macros defined in another
> file if you have loaded their definitions first.
> 
> Who made an argument against ever using macros? Certainly not me.
> 
> I think that build processes that compile everything before they load
> it are fine, but those things better not have any macros in them.  If
> they are compiling macros, they should stop and load the macros before
> proceeding.  Macros are like extending the "language level".
> Everything written using macros is in a new language that must be
> loaded before it can be compiled or executed.
> 

which prompted me to look again at cltl2 and clhs, and to observe that, while steele writes

"If the compiler encounters a defmacro, the new macro is added to the compilation environment, and a compiled form of the expansion function is also added to
the output file so that the new macro will be operative at run time. If this is not the desired effect, the defmacro form can be wrapped in an eval-when construct."

the spec says 

"If a defmacro form appears as a top level form, the compiler must store the macro definition at compile time, so that occurrences of the macro later on in the
file can be expanded correctly. Users must ensure that the body of the macro can be evaluated at compile time if it is referenced within the file being compiled."

which makes me ask whether the "compilation environment" is specified to extend over the immediate file only? i looked, but found no explicit specification of
its extent.

...
From: Kent M Pitman
Subject: Re: eval-when needed?
Date: 
Message-ID: <sfw8yvm8i5s.fsf@shell01.TheWorld.com>
james anderson <··············@setf.de> writes:

> Kent M Pitman wrote:
> > 
> > ...
> > 
> > I don't think there is a problem with using macros defined in another
> > file if you have loaded their definitions first.
> > 
> > Who made an argument against ever using macros? Certainly not me.
> > 
> > I think that build processes that compile everything before they load
> > it are fine, but those things better not have any macros in them.  If
> > they are compiling macros, they should stop and load the macros before
> > proceeding.  Macros are like extending the "language level".
> > Everything written using macros is in a new language that must be
> > loaded before it can be compiled or executed.
> > 
> 
> which prompted me to look again at cltl2 and clhs, and to observe that, while steele writes
> 
> "If the compiler encounters a defmacro, the new macro is added to the compilation environment, and a compiled form of the expansion function is also added to
> the output file so that the new macro will be operative at run time. If this is not the desired effect, the defmacro form can be wrapped in an eval-when construct."
> 
> the spec says 
> 
> "If a defmacro form appears as a top level form, the compiler must store the macro definition at compile time, so that occurrences of the macro later on in the
> file can be expanded correctly. Users must ensure that the body of the macro can be evaluated at compile time if it is referenced within the file being compiled."
> 
> which makes me ask whether the "compilation environment" is specified to extend over the immediate file only? i looked, but found no explicit specification of
> its extent.
> 
> ...

It extends at least that far, and is allowed as an implementational detail
to extend farther, but not required to.

For example, in some implementations
(and I think Kyoto Common Lisp did this (and I don't know if it went on to do
this in its later incarnations, which might include Gnu CL)), compile-file
spawned a different operating-system-level process (i.e., with its own
address space) that did the compilation and then exited.  I don't know the
details of this--I just remember it confounded a lot of people.  Maybe it
cloned the current state of the existing process as its starting point?

It's also permissible, and I don't know if anyone implements this, but
I don't think so, to actually have a separate "compiler environment"
object that somehow gets side-effected instead of the lisp runtime
that is invoking compile-file.  The reason I don't think anyone does
this is that the package system and various other system objects make
it such that it's hard to really imagine there being sufficient
segmentation between such things in order that there not be any effect
at compile-time that wouldn't leak into the runtime.  eval-when allows
the running of a turing machine, and it's likely that some aspect of
that is unpredictable enough to cause a problem.

So in practice, the "compile time" and the "runtime" of the lisp in
which compile-file run are usually the same thing, but not
definitionally so.  It's bad style to write code that depends on this.
So when you compile things, it's best to just load them.  We used to
not do that in order to save address space, by loading only what was
essential, and leaving out things that were logical components as
"unnecessary", but in modern large address space and large disk space
systems, this is a total non-issue.  (There might sometimes be a security
issue that keeps someone from loading a critical compile-time-only key
or facility that you don't want in your distributed issue, but that would
be a special case.  When I say something is "not good style" that doesn't
mean you must never do it; it means you must never do it without an 
overriding reason that acknowledges the style rule but finds still another
more powerful reason to not do the thing.)
From: james anderson
Subject: Re: eval-when needed?
Date: 
Message-ID: <3E6DB9DC.8FB3C471@setf.de>
Kent M Pitman wrote:
> 
> >
> > which makes me ask whether the "compilation environment" is specified to extend over the immediate file only? i looked, but found no explicit specification of
> > its extent.
> >
> > ...
> 
> It extends at least that far, and is allowed as an implementational detail
> to extend farther, but not required to.
> 
> For example, in some implementations
> (and I think Kyoto Common Lisp did this (and I don't know if it went on to do
> this in its later incarnations, which might include Gnu CL)), compile-file
> spawned a different operating-system-level process (i.e., with its own
> address space) that did the compilation and then exited.  I don't know the
> details of this--I just remember it confounded a lot of people.  Maybe it
> cloned the current state of the existing process as its starting point?
> 

this is one of those things which doesn't confuse one until one starts to think about it. there is a distinction between "the compiler must evaluate the body at
compile time", as follows from (eval-when (:compile-toplevel)), and "the new macro is added to the compilation environment" or (ignoring the succeeding clause)
"the compiler must store the macro definition at compile time", which one must be careful not to overlook.

especially when the passages in steele which discuss compile-time side effects in connection with x3j13 decisions suggest, after noting the file extent, that "A
convenient model for explaining how these side effects happen is that each defining macro expands into one or more eval-when forms and that compile-time side
effects are caused by calls occurring in the body of an (eval-when (:compile-toplevel) ...) form.", but then proceeds, two pages later, to clarify, that
"Compile-time side effects may cause information about a definition to be stored in a different manner from information about definitions processed either
interpretively or by loading a compiled file," and to demonstrate that :compile-toplevel was not really the right model.

and, in particular, when i look at the workings of my local lisp runtime, i observe that they go to some length to exclude :compile-toplevel:

? (pprint (macroexpand '(defmacro asdf (a b) `(+ ,a ,b))))

(PROGN (EVAL-WHEN (:COMPILE-TOPLEVEL)
         (CCL::DEFINE-COMPILE-TIME-MACRO
           'ASDF
           '(LAMBDA (#:G8 #:G9)
              (DECLARE (IGNORE-IF-UNUSED #:G9))
              (CCL::MACRO-BIND (A B)
                               #:G8
                               (BLOCK ASDF (LIST* '+ (LIST* A (LIST B))))))
           'NIL))
       (EVAL-WHEN (:LOAD-TOPLEVEL :EXECUTE)
         (CCL::%MACRO (NFUNCTION ASDF
                                 (LAMBDA (#:G8 #:G9)
                                   (DECLARE (IGNORE-IF-UNUSED #:G9))
                                   (CCL::MACRO-BIND (A B)
                                                    #:G8
                                                    (BLOCK
                                                     ASDF
                                                     (LIST*
                                                      '+
                                                      (LIST* A (LIST B)))))))
                      '(NIL NIL . "(A B)"))
         'ASDF))

? is there some reason why one wants to stongly isolate the evaluation environment from the compile environment?

? what would an implementation of the KCL sort do about eval-when? 

...
From: Kent M Pitman
Subject: Re: eval-when needed?
Date: 
Message-ID: <sfwwuj653w1.fsf@shell01.TheWorld.com>
james anderson <··············@setf.de> writes:

> and, in particular, when i look at the workings of my local lisp runtime, i observe that they go to some length to exclude :compile-toplevel:
> 
> ? (pprint (macroexpand '(defmacro asdf (a b) `(+ ,a ,b))))
> 
> (PROGN (EVAL-WHEN (:COMPILE-TOPLEVEL)
>          (CCL::DEFINE-COMPILE-TIME-MACRO
>            'ASDF
>            '(LAMBDA (#:G8 #:G9)
>               (DECLARE (IGNORE-IF-UNUSED #:G9))
>               (CCL::MACRO-BIND (A B)
>                                #:G8
>                                (BLOCK ASDF (LIST* '+ (LIST* A (LIST B))))))
>            'NIL))
>        (EVAL-WHEN (:LOAD-TOPLEVEL :EXECUTE)
>          (CCL::%MACRO (NFUNCTION ASDF
>                                  (LAMBDA (#:G8 #:G9)
>                                    (DECLARE (IGNORE-IF-UNUSED #:G9))
>                                    (CCL::MACRO-BIND (A B)
>                                                     #:G8
>                                                     (BLOCK
>                                                      ASDF
>                                                      (LIST*
>                                                       '+
>                                                       (LIST* A (LIST B)))))))
>                       '(NIL NIL . "(A B)"))
>          'ASDF))
> 
> ? is there some reason why one wants to stongly isolate the
>   evaluation environment from the compile environment?
 
Sure.  To help you remember to call LOAD, so that implementations
which differ in these details are not as easily caught differing.  If
you write your code the right way, seeing the internals is irrelevant.
If you do not, you spend forever macroexpanding things to figure out
why stuff is not working because you are relying on things that (a)
you ought not and (b) that can legitimately vary among
implementations.


> ? what would an implementation of the KCL sort do about eval-when? 
> 
> ...

I don't know for sure; I never used it. However, my impression has always
been that it would use the first, :compile-toplevel, definition for the
duration of the compilation unit and the second, :load-toplevel, definition
in any environment in which you called LOAD to get this code drawn in.

Note, ofcourse, that these are implementation-dependent expansions and this
code is not required to work in some other implementation; KCL would, in 
fact, have its own set of bookkeeping to be done in these situations which
might be utterly different.  That doesn't mean your question doesn't make
sense, which is why I answered it; however, it may mean your question is
still capable of confusing you, which I'll merely note as a possibility.
From: james anderson
Subject: Re: eval-when needed?
Date: 
Message-ID: <3E6E22ED.EC6C36CB@setf.de>
the question about kcl is unrelated to mcl's macro expansion.
if was wondering how it would effect a compile-time-too mode at all, given that
the compiler is in a separate process.

...

Kent M Pitman wrote:
> 
> ...
> 
> > ? what would an implementation of the KCL sort do about eval-when?
> >
> > ...
> 
> I don't know for sure; I never used it. However, my impression has always
> been that it would use the first, :compile-toplevel, definition for the
> duration of the compilation unit and the second, :load-toplevel, definition
> in any environment in which you called LOAD to get this code drawn in.
> 
> Note, ofcourse, that these are implementation-dependent expansions and this
> code is not required to work in some other implementation; KCL would, in
> fact, have its own set of bookkeeping to be done in these situations which
> might be utterly different.  That doesn't mean your question doesn't make
> sense, which is why I answered it; however, it may mean your question is
> still capable of confusing you, which I'll merely note as a possibility.
From: Tim Bradshaw
Subject: Re: eval-when needed?
Date: 
Message-ID: <ey3n0k29ool.fsf@cley.com>
* james anderson wrote:

> ? is there some reason why one wants to stongly isolate the evaluation environment from the compile environment?

Sure.  If I write a file with a new version of some macro in it, and
compile it but do not load it, I may still want to compile some other
file which has the old macros in, for instance (this is a fairly weird
case).  Even more so: if I compile a file which defines a function, I
definitely do *not* want that function to become defined in my
environment: that's what loading is for.

--tim
From: Kent M Pitman
Subject: Re: eval-when needed?
Date: 
Message-ID: <sfwvfym866v.fsf@shell01.TheWorld.com>
Tim Bradshaw <···@cley.com> writes:

> * james anderson wrote:
> 
> > ? is there some reason why one wants to stongly isolate the evaluation
> >   environment from the compile environment?
> 
> Sure.  If I write a file with a new version of some macro in it, and
> compile it but do not load it, I may still want to compile some other
> file which has the old macros in, for instance (this is a fairly weird
> case).  Even more so: if I compile a file which defines a function, I
> definitely do *not* want that function to become defined in my
> environment: that's what loading is for.

Yes.  It may help for some people to conceptualize this by
understanding that on the Lisp Machine, your Lisp image is your
operating system.  When compiling side-effects the running image, it
means that the change is permanent until you boot your machine.
People have often kept Lisp Machines running for the better part of a
year, and that didn't happen by having every kludgey macro that you
compiled end up side-effecting the world you're running.  One wants
strong control of the content of the world they're in if they're going
to stay up for a very long time...   Not that you can't sometimes do
DELETE-PACKAGE and a big GC and then reload some things, but that's kind
of a big hammer, and it only works for certain non-critical packages
that are not relied upon by the system itself.
From: Tim Bradshaw
Subject: Re: eval-when needed?
Date: 
Message-ID: <ey3r89am3tx.fsf@cley.com>
* Kent M Pitman wrote:

> Yes.  It may help for some people to conceptualize this by
> understanding that on the Lisp Machine, your Lisp image is your
> operating system.  When compiling side-effects the running image, it
> means that the change is permanent until you boot your machine.

Even for non-OS lisps, restarting a Lisp which you are using for
development can be a really big pain.  I *often* run the same image
for days, and it can take a good long time to get back to the state I
was in if I have to restart it, because I don't keep records of all
the functions I happen to have traced & hundreds of other things like
that, and quite often I've been sitting in the debugger for ages
trying to fix something, and the state of the stack matters.

(You know this, of course!)

--tim
From: Pekka P. Pirinen
Subject: Re: eval-when needed?
Date: 
Message-ID: <uel5d7t6o.fsf@globalgraphics.com>
[reformatted]
james anderson <··············@setf.de> writes:

> the passages in steele [...] suggest [...] that "A convenient model
> for explaining how these side effects happen is that each defining
> macro expands into one or more eval-when forms and that compile-time
> side effects are caused by calls occurring in the body of an
> (eval-when (:compile-toplevel) ...) form.", but then proceeds, two
> pages later, to clarify, that "Compile-time side effects may cause
> information about a definition to be stored in a different manner
> from information about definitions processed either interpretively
> or by loading a compiled file," and to demonstrate that
> :compile-toplevel was not really the right model.

It doesn't imply :COMPILE-TOPLEVEL is not the right model, merely that
the code that is wrapped in the (EVAL-WHEN (:COMPILE-TOPLEVEL) ...)
does not need to be the same code that is used for the other
processing times.  (And it usually isn't.  What would've been the
point of using an EVAL-WHEN with only :COMPILE-TOPLEVEL, if it
wasn't?)  I think Steele presented this model in order to clarify
processing order (and to demonstrate how to write your own defining
macros).

> when i look at the workings of my local lisp runtime, i observe that
> they go to some length to exclude :compile-toplevel:

Not exclude, separate.

This is mostly because compilers find it convenient to store
environment information in different format, and to omit those parts
of it that are only used at run time.

> ? is there some reason why one wants to stongly isolate the
> evaluation environment from the compile environment?

Like I said, this mostly done to streamline the compiler.  However,
isolating the two environments does make cross-compilation easier: The
compilation environment contains definitions pertaining to the target
and the evaluation environment to the source.  This applies not only
to cross-compilation across platforms, but also to recompiling a any
system across a major change in its macrology (even if everything has
been compiled using the old macro definitions to begin with, the
compilation might need to execute the macros interpreted during an
(EVAL-WHEN (:COMPILE-TOPLEVEL) ..)).
-- 
Pekka P. Pirinen
There is enough in the world for man's need, but not for his greed.
    - Gandhi
From: Barry Margolin
Subject: Re: eval-when needed?
Date: 
Message-ID: <2H3ea.10$F4.662@paloalto-snr1.gtei.net>
In article <·················@setf.de>,
james anderson  <··············@setf.de> wrote:
>especially when the passages in steele which discuss compile-time side
>effects in connection with x3j13 decisions suggest, after noting the file
>extent, that "A
>convenient model for explaining how these side effects happen is that
>each defining macro expands into one or more eval-when forms and that
>compile-time side
>effects are caused by calls occurring in the body of an (eval-when
>(:compile-toplevel) ...) form.", but then proceeds, two pages later, to
>clarify, that
>"Compile-time side effects may cause information about a definition to be
>stored in a different manner from information about definitions processed
>either
>interpretively or by loading a compiled file," and to demonstrate that
>:compile-toplevel was not really the right model.

EVAL-WHEN *is* a good model for understanding how these side effects
happen.  However, you have to understand that the functions called within
the body of the EVAL-WHEN at compile time are not likely to be the ones you
expect.  E.g. DEFMACRO's expansion might contain something like:

(eval-when (:compile-toplevel)
  (setf (system:compile-time-macro-binding ',name) ...))

rather than what you seem to assume:

(eval-when (:compile-toplevel)
  (setf (symbol-macro ',name) ...))

Some macros are simple enough that they can use the same expansion at
compile and load/eval times, e.g.

(defmacro in-package (package)
  `(eval-when (:compile-toplevel :execute :load-toplevel)
     (setq *package* (find-package ',package))))

but this is probably the exception, not the general rule.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Barry Margolin
Subject: Re: eval-when needed?
Date: 
Message-ID: <Ku3ea.9$F4.631@paloalto-snr1.gtei.net>
In article <·················@setf.de>,
james anderson  <··············@setf.de> wrote:
>is the argument against build processes which compile "everything" before
>they load it implicit or explicit?

Implicit.

Think of it this way: loading is the way you use something in a file.
Compiling merely makes it so that the loaded version will run faster.

Although CL allows for some interaction between the run-time and
compile-time environments, it's not a good idea to depend on them
extensively.  You don't generally need to compile as often as you load.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kaz Kylheku
Subject: Re: eval-when needed?
Date: 
Message-ID: <cf333042.0303111109.7e553928@posting.google.com>
Peter Seibel <·····@javamonkey.com> wrote in message news:<··············@localhost.localdomain>...
> So I'm back to trying to understand eval-when. I think I've mostly got
> it but I just wanted to check one thing. Suppose I have a file that
> defines a bunch of functions, variables (defvars), classes, etc. and
> some macros that use them (calling the functions, stuffing bits of
> data into the variables that will be used by the other macros during
> their expansion, etc.)

EVAL-WHEN is needed because a Lisp program may be processed in
different situations.

In a programming language like C, you have a clear division between
the translation environment and the execution environment. You know
that in the translation environment, you can do some simple evaluation
in the preprocessor like #if defined FOO || defined BAR, and you know
that in this environment, you can't call the printf function; the
stages of translation of the program are tied to the environment in a
straightforward way.

The environment distinctions don't go away in Lisp, but the full
language is available in any stage of processing. It's still possible
to do things like compile a program on your developer workstation, but
run it somewhere else, like a user's machine, or an embedded system,
etc; in other words, to translate code in one environment, and execute
in another. In the Lisp terminology, the different situations in which
code is processed are called times: compile time, load time, etc.

When you interact with a Lisp system, you can type expressions into a
listener and they are evaluated; if you define a variable or function,
it goes into your image, and you can recall it.

But you can also tell your Lisp system to compile a file, which will
cause it to read the Lisp objects in that file, process them as source
code, and then deposit some compiled image into another file. In this
process, it would be undesirable if the top-level definitions in that
file became active in the image in which the compiler runs; that would
be considered pollution. Only if you actually LOAD these files (or
their corresponding compiled images) do you want these definitions to
come into effect. So the compiler does not actually evaluate top-level
forms; it merely translates them from source code form into some other
form.

The most common use of EVAL-WHEN is to override this behavior; to say,
yes I do want these top level forms to be evaluated in the compiler's
context, and I understand and accept that these forms may introduce
variables, functions or other things into that environment. The need
to do this arises commonly when you have some code that is invoked at
compile time, such as macros, and those macros are too complex to be
self-contained; you want to factor out their transformations into
functions whose definitions must be available at the time the macro is
called upon to do expansion.
 
> A trivial (and silly) example of what I'm talking about is something
> like this:
> 
>   (defpackage "SNIPPETS"
>     (:use "COMMON-LISP")
>     (:export "DEFSNIPPET" "DEFCODE"))
> 
>   (in-package "SNIPPETS")
> 
>   (defvar *snippets* (make-hash-table))
> 
>   (defmacro defsnippet (name &body snippet)
>     `(eval-when (:compile-toplevel :load-toplevel :execute)
>       (setf (gethash ',name *snippets*) ',@snippet)))

Here, the EVAL-WHEN is probably not necessary, unless these
manipulations of the *snippets* hash table must be visible in all
three specified times. But in that case, you must also subordinate the
DEFVAR to an EVAL-WHEN! The two must be in parallel; if a computation
is to be evaluated in situations X, Y and Z, then any variable it
refers to must be available in situations X, Y and Z, and so the
definition of that variable must be evaluated in those situations.

Suppose that the Lisp compiler encounters a file that contains:

   (defsnippet foo ...)

Because of the EVAL-WHEN which specifies :COMPILE-TOPLEVEL, it will
evaluate the (SETF (GETHASH ...) ..).  And of course this will
probably fail, because the variable *snippets* probably does not
exist, because when the compiler processed the DEFVAR in the other
source file, it merely translated that DEFVAR into some compiled
instructions in the corresopnding .FASL file, but did not actually
create the variable in memory. Now through EVAL-WHEN, you are asking
the compiler to refer to a *snippets* variable in memory.