From: Tim Bradshaw
Subject: EVAL-WHEN question (and maybe a bug in clisp/cmucl)
Date: 
Message-ID: <ey3og4fxgr8.fsf@cley.com>
I need to prevent the expansion of a macro which expands into an
(eval-when (:compile-toplvel :load-toplevel :execute ...) ...) form
from being evaluated until load time.

Wrapping it in (eval-when (:load-toplevel) ...) is not enough, because
the body of the eval-when is processed by the compiler as a toplevel
form, and since this form says to actually evaluate it I lose.

But I reckon that wrapping it in (let () ...) should do the trick, as
LET is not one of the things that preserve toplevelness, so the
eval-when is then not at toplevel, and all is well.  This works OK in
Allegro and Genera.  But CLISP and CMUCL both complain because they
try and evaluate the expansion at compile-time.

Am I right in how I think this should work?

If so (or in any case), is there any other way of stopping the
expansions of macros that expand like this from being evaluated at
compile time?  I tried various obvious hacks like wrapping things in
((lambda () ...)) but they didn't work.  Splitting it into two files
is an obvious trick, but I want to avoid it for now.

(The reason I need to do this is because I have code which defines a
souped-up DEFPACKAGE macro, and then (at load time) uses it to define
some packages. The expansion of DEFPACKAGE needs to be evaluated at
compile time, in general, but I need these uses in my code from being
evaluated at compile time as not all the infrastructure exists then.)

--tim

From: Erik Naggum
Subject: Re: EVAL-WHEN question (and maybe a bug in clisp/cmucl)
Date: 
Message-ID: <3171635287685623@naggum.net>
* Tim Bradshaw <···@cley.com>
| Wrapping it in (eval-when (:load-toplevel) ...) is not enough, because
| the body of the eval-when is processed by the compiler as a toplevel
| form, and since this form says to actually evaluate it I lose.

  This seems _really_ bogus to me.  Once you exclude :compile-toplevel
  and especially :execute from the eval-when situations, the compiler
  should only cause the form to be evaluated/executed at load-time.

#:Erik
-- 
  If this is not what you expected, please alter your expectations.
From: Tim Bradshaw
Subject: Re: EVAL-WHEN question (and maybe a bug in clisp/cmucl)
Date: 
Message-ID: <ey3lmzjxb4h.fsf@cley.com>
* Erik Naggum wrote:
* Tim Bradshaw <···@cley.com>
> | Wrapping it in (eval-when (:load-toplevel) ...) is not enough, because
> | the body of the eval-when is processed by the compiler as a toplevel
> | form, and since this form says to actually evaluate it I lose.

>   This seems _really_ bogus to me.  Once you exclude :compile-toplevel
>   and especially :execute from the eval-when situations, the compiler
>   should only cause the form to be evaluated/executed at load-time.

Yes, that was what I thought too, but it doesn't appear to be right.

This code:

    (eval-when (:load-toplevel)
      (progn
	(eval-when (:compile-toplevel :load-toplevel :execute)
	  (this-function-does-not-exist))))

Causes ACL to barf at compile time, and it seems to be correct so to
do.  I always have a hard time understanding what happens when in
strange cases like this, but it looks to me like the table in section
3.2.3.1 of the spec says:

Before the outer eval-when the compiler is in not-compile-time mode
and at top-level (by assumption).  When it sees the outer eval-when it
processes its body in this same mode. It jumps across PROGN remaining
at top-level.  The inner eval-when then pushes it into
compile-time-too mode, and the body ends up evaluated by the compiler.

I think this behaviour is horrible actually, so I worry I've
misunderstood it.  But ACL and Genera are both completely consistent
about it.  CMUCL and CLISP are consistently worse in that they will
cross a LET and remain at top-level.

I'd be really glad to be proved wrong about this, actually!

--tim