Common Lisp the Language, 2nd Edition
Next: Predicates
Up: Top-Level Forms
Previous: Declaring Global
Variables
The eval-when
special form allows pieces of code to be
executed only at compile time, only at load time, or when interpreted
but not compiled. Its uses are relatively esoteric.
[Special Form]
eval-when
({
situation
}*)
{
form
}*
The body of an eval-when
form is processed as an
implicit progn
, but only in the situations listed. Each
situation must be a symbol, either compile
,
load
, or eval
.
eval
specifies that the interpreter should process the
body. compile
specifies that the compiler should evaluate
the body at compile time in the compilation context. load
specifies that the compiler should arrange to evaluate the forms in the
body when the compiled file containing the eval-when
form
is loaded.
The eval-when
construct may be more precisely understood
in terms of a model of how the compiler processes forms in a file to be
compiled. Successive forms are read from the file using the function
read
. These top-level forms are normally processed in what
we shall call not-compile-time mode. There is another mode
called compile-time-too mode. The eval-when
special form controls which of these two modes to use.
Every form is processed as follows:
eval-when
form:
load
is specified:
compile
is specified, or if
the current processing mode is compile-time-too and the
situation eval
is specified, then process each of the forms
in the body in compile-time-too mode.load
is not specified:
compile
is specified, or if
the current processing mode is compile-time-too and the
situation eval
is specified, then evaluate each of the
forms in the body in the compiler’s executing environment.eval-when
form entirely.eval-when
form, then do two
things. First, if the current processing mode is
compile-time-too mode, evaluate the form in the compiler’s
executing environment. Second, perform normal compiler processing of the
form (compiling functions defined by defun
forms, and so
on).One example of the use of eval-when
is that if the
compiler is to be able to properly read a file that uses user-defined
reader macro characters, it is necessary to write
(eval-when (compile load eval)
(set-macro-character #\$ #'(lambda (stream char)
(declare (ignore char))
(list 'dollar (read stream)))))
This causes the call to set-macro-character
to be
executed in the compiler’s execution environment, thereby modifying its
reader syntax table.
X3J13 voted in March 1989 (EVAL-WHEN-NON-TOP-LEVEL) to completely
redesign the eval-when
construct to solve some problems
concerning its treatment in other than top-level contexts. The new
definition is upward compatible with the old definition, but the old
keywords are deprecated.
[Special Form]
eval-when
({
situation
}*)
{
form
}*
The body of an eval-when
form is processed as an
implicit progn
, but only in the situations listed. Each
situation must be a symbol, either
:compile-toplevel
, :load-toplevel
, or
:execute
.
The use of :compile-toplevel
and
:load-toplevel
controls whether and when processing occurs
for top-level forms. The use of :execute
controls whether
processing occurs for non-top-level forms.
The eval-when
construct may be more precisely understood
in terms of a model of how the file compiler, compile-file
,
processes forms in a file to be compiled.
Successive forms are read from the file by the file compiler using
read
. These top-level forms are normally processed in what
we call ``not-compile-time’’ mode. There is one other mode, called
``compile-time-too’’ mode, which can come into play for top-level forms.
The eval-when
special form is used to annotate a program in
a way that allows the program doing the processing to select the
appropriate mode.
Processing of top-level forms in the file compiler works as follows:
If the form is a macro call, it is expanded and the result is processed as a top-level form in the same processing mode (compile-time-too or not-compile-time).
If the form is a progn
(or locally
(LOCALLY-TOP-LEVEL) ) form, each of its body forms is sequentially
processed as top-level forms in the same processing mode.
If the form is a compiler-let
,
macrolet
, or symbol-macrolet
, the file
compiler makes the appropriate bindings and recursively processes the
body forms as an implicit top-level progn
with those
bindings in effect, in the same processing mode.
If the form is an eval-when
form, it is handled
according to the following table:
In the preceding table the column LT asks whether
:load-toplevel
is one of the situations specified in the
eval-when
form; CT similarly refers to
:compile-toplevel
and EX to :execute
. The
column CTTM asks whether the eval-when
form was encountered
while in compile-time-too mode. The phrase ``process body’’ means to
process the body as an implicit top-level progn
in the
indicated mode, and ``evaluate body’’ means to evaluate the body forms
sequentially as an implicit progn
in the dynamic execution
context of the compiler and in the lexical environment in which the
eval-when
appears.
Otherwise, the form is a top-level form that is not one of the special cases. If in compile-time-too mode, the compiler first evaluates the form and then performs normal compiler processing on it. If in not-compile-time mode, only normal compiler processing is performed (see section 25.1). Any subforms are treated as non-top-level forms.
Note that top-level forms are guaranteed to be processed in the order in which they textually appear in the file, and that each top-level form read by the compiler is processed before the next is read. However, the order of processing (including, in particular, macro expansion) of subforms that are not top-level forms is unspecified.
For an eval-when
form that is not a top-level form in
the file compiler (that is, either in the interpreter, in
compile
, or in the file compiler but not at top level), if
the :execute
situation is specified, its body is treated as
an implicit progn
. Otherwise, the body is ignored and the
eval-when
form has the value nil
.
For the sake of backward compatibility, a situation may also
be compile
, load
, or eval
. Within
a top-level eval-when
form these have the same meaning as
:compile-toplevel
, :load-toplevel
, and
:execute
, respectively; but their effect is undefined when
used in an eval-when
form that is not at top level.
The following effects are logical consequences of the preceding specification:
It is never the case that the execution of a single
eval-when
expression will execute the body code more than
once.
The old keyword eval
was a misnomer because execution of
the body need not be done by eval
. For example, when the
function definition
(defun foo () (eval-when (:execute) (print 'foo)))
is compiled the call to print
should be compiled, not
evaluated at compile time.
Macros intended for use in top-level forms should arrange for all side-effects to be done by the forms in the macro expansion. The macro-expander itself should not perform the side-effects.
(defmacro foo ()
(really-foo) ;Wrong
`(really-foo))
(defmacro foo ()
`(eval-when (:compile-toplevel
:load-toplevel :execute) ;Right
(really-foo)))
Adherence to this convention will mean that such macros will behave intuitively when called in non-top-level positions.
Placing a variable binding around an eval-when
reliably
captures the binding because the ``compile-time-too’’ mode cannot occur
(because the eval-when
could not be a top-level form). For
example,
(let ((x 3))
(eval-when (:compile-toplevel :load-toplevel :execute)
(print x)))
will print 3 at execution (that is, load) time and will not print
anything at compile time. This is important so that expansions of
defun
and defmacro
can be done in terms of
eval-when
and can correctly capture the lexical
environment. For example, an implementation might expand a
defun
form such as
(defun bar (x) (defun foo () (+ x 3)))
into
(progn (eval-when (:compile-toplevel)
(compiler::notice-function 'bar '(x)))
(eval-when (:load-toplevel :execute)
(setf (symbol-function 'bar)
#'(lambda (x)
(progn (eval-when (:compile-toplevel)
(compiler::notice-function 'foo
'()))
(eval-when (:load-toplevel :execute)
(setf (symbol-function 'foo)
#'(lambda () (+ x 3)))))))))
which by the preceding rules would be treated the same as
(progn (eval-when (:compile-toplevel)
(compiler::notice-function 'bar '(x)))
(eval-when (:load-toplevel :execute)
(setf (symbol-function 'bar)
#'(lambda (x)
(progn (eval-when (:load-toplevel :execute)
(setf (symbol-function 'foo)
#'(lambda () (+ x 3)))))))))
Here are some additional examples.
(let ((x 1))
(eval-when (:execute :load-toplevel :compile-toplevel)
(setf (symbol-function 'foo1) #'(lambda () x))))
The eval-when
in the preceding expression is not at top
level, so only the :execute
keyword is considered. At
compile time, this has no effect. At load time (if the let
is at top level), or at execution time (if the let
is
embedded in some other form which does not execute until later), this
sets (symbol-function 'foo1)
to a function that returns
1
.
(eval-when (:execute :load-toplevel :compile-toplevel)
(let ((x 2))
(eval-when (:execute :load-toplevel :compile-toplevel)
(setf (symbol-function 'foo2) #'(lambda () x)))))
If the preceding expression occurs at the top level of a file to be
compiled, it has both a compile time and a load-time
effect of setting (symbol-function 'foo2)
to a function
that returns 2
.
(eval-when (:execute :load-toplevel :compile-toplevel)
(setf (symbol-function 'foo3) #'(lambda () 3)))
If the preceding expression occurs at the top level of a file to be
compiled, it has both a compile time and a load-time
effect of setting the function cell of foo3
to a function
that returns 3
.
(eval-when (:compile-toplevel)
(eval-when (:compile-toplevel)
(print 'foo4)))
The preceding expression always does nothing; it simply returns
nil
.
(eval-when (:compile-toplevel)
(eval-when (:execute)
(print 'foo5)))
If the preceding form occurs at the top level of a file to be
compiled, foo5
is printed at compile time. If this form
occurs in a non-top-level position, nothing is printed at compile time.
Regardless of context, nothing is ever printed at load time or execution
time.
(eval-when (:execute :load-toplevel)
(eval-when (:compile-toplevel)
(print 'foo6)))
If the preceding form occurs at the top level of a file to be
compiled, foo6
is printed at compile time. If this form
occurs in a non-top-level position, nothing is printed at compile time.
Regardless of context, nothing is ever printed at load time or execution
time.
Next: Predicates
Up: Top-Level Forms
Previous: Declaring Global
Variables
AI.Repository@cs.cmu.edu