|
ANSI Common Lisp 3 Evaluation and Compilation 3.8 Dictionary Evaluation and Compilation
3.8.5 eval-when |
Special Operator |
- Syntax:
-
eval-when
({situation}*) {form}*
{result}*
- Arguments and Values:
-
situation - One of the symbols
:compile-toplevel,
:load-toplevel,
:execute,
compile,
load, or
eval.
The use of eval, compile, and load is deprecated.
forms - an implicit progn.
results - the values of the forms if they are executed,
or nil if they are not.
- Description:
-
The body of an eval-when form is processed as an implicit progn,
but only in the situations listed.
The use of the situations :compile-toplevel (or compile) and
:load-toplevel (or load) controls whether and when evaluation
occurs when eval-when appears as a top level form in
code processed by compile-file. See Section 3.2.3 File Compilation.
The use of the situation :execute (or eval) controls whether
evaluation occurs for other eval-when forms; that is,
those that are not top level forms, or those in code processed by
eval or compile. If the :execute situation is
specified in such a form, then the body forms are processed as
an implicit progn; otherwise, the eval-when form
returns nil.
eval-when
normally appears as a top level form, but it is meaningful
for it to appear as a non-top-level form.
However, the compile-time side
effects described in Section 3.2 Compilation
only take place when eval-when appears as a
top level form.
- Examples:
-
One example of the use of eval-when is that for the
compiler to be able to read a file properly when it uses user-defined
reader macros, it is necessary to write
(eval-when (:compile-toplevel :load-toplevel :execute)
(set-macro-character #\$ #'(lambda (stream char)
(declare (ignore char))
(list 'dollar (read stream))))) T
This causes the call to set-macro-character to be executed
in the compiler's execution environment, thereby modifying its
reader syntax table.
;;; The EVAL-WHEN in this case is not at toplevel, so only the :EXECUTE
;;; keyword is considered. At compile time, this has no effect.
;;; At load time (if the LET is at toplevel), 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 which
;;; returns 1.
(let ((x 1))
(eval-when (:execute :load-toplevel :compile-toplevel)
(setf (symbol-function 'foo1) #'(lambda () x))))
;;; If this expression occurs at the toplevel 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 which returns 2.
(eval-when (:execute :load-toplevel :compile-toplevel)
(let ((x 2))
(eval-when (:execute :load-toplevel :compile-toplevel)
(setf (symbol-function 'foo2) #'(lambda () x)))))
;;; If this expression occurs at the toplevel 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 which returns 3.
(eval-when (:execute :load-toplevel :compile-toplevel)
(setf (symbol-function 'foo3) #'(lambda () 3)))
;;; #4: This always does nothing. It simply returns NIL.
(eval-when (:compile-toplevel)
(eval-when (:compile-toplevel)
(print 'foo4)))
;;; If this form occurs at toplevel 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 (:compile-toplevel)
(eval-when (:execute)
(print 'foo5)))
;;; If this form occurs at toplevel 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.
(eval-when (:execute :load-toplevel)
(eval-when (:compile-toplevel)
(print 'foo6)))
- See Also:
-
compile-file, Section 3.2 Compilation
- Notes:
-
The following effects are logical consequences of the definition of
eval-when:
-
Execution of a single eval-when
expression executes the body code at most once.
-
Macros intended for use in top level forms
should be written so that side-effects are done by the forms
in the macro expansion. The macro-expander itself should not do
the side-effects.
For example:
Wrong:
(defmacro foo ()
(really-foo)
`(really-foo))
Right:
(defmacro foo ()
`(eval-when (:compile-toplevel :execute :load-toplevel) (really-foo)))
Adherence to this convention means that such macros behave
intuitively when appearing as non-top-level forms.
-
Placing a variable binding around an eval-when reliably
captures the binding because the compile-time-too mode cannot occur
(i.e., introducing a variable binding means that the eval-when
is not a top level form).
For example,
(let ((x 3))
(eval-when (:execute :load-toplevel :compile-toplevel) (print x)))
prints 3
at execution (i.e., load) time, and does 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.
(defun bar (x) (defun foo () (+ x 3)))
might expand into
(defun bar (x)
(progn (eval-when (:compile-toplevel)
(compiler::notice-function-definition 'foo '(x)))
(eval-when (:execute :load-toplevel)
(setf (symbol-function 'foo) #'(lambda () (+ x 3))))))
which would be treated by the above rules the same as
(defun bar (x)
(setf (symbol-function 'foo) #'(lambda () (+ x 3))))
when the definition of bar is not a top level form.
- Allegro CL Implementation Details:
-
None.
|