EVAL-WHEN(3cl) |
Common Lisp Reference |
EVAL-WHEN(3cl) |
NAME
eval-when – evaluate forms, but only in specified situations (special operator)
SYNOPSIS
|
ARGUMENTS and VALUES
:compile-toplevel, :load-toplevel, :execute, compile, load, or eval. The use of eval, compile, and load is deprecated. —One of the symbols
progn. —an implicit
nil if they are not. —the values of the if they are executed, or
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.
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, certain compile-time side effects only take place when eval-when appears as a top level form.
AFFECTED BY
(none)
EXCEPTIONAL SITUATIONS
(none)
NOTES
The function compile-file performs compilation of forms in a file, and produces an output file that can be loaded by using load. Normally, the top level forms appearing in a file compiled with compile-file are evaluated only when the resulting compiled file is loaded, and not when the file is compiled. However, it is typically the case that some forms in the file need to be evaluated at compile time so the remainder of the file can be read and compiled correctly.
The eval-when special form can be used to control whether a top level form is evaluated at compile time, load time, or both. It is possible to specify any of three situations with eval-when.
For top level eval-when forms, :compile-toplevel specifies that the compiler must evaluate the body at compile time, and :load-toplevel specifies that the compiler must arrange to evaluate the body at load time.
For non-top level eval-when forms, :execute specifies that the body must be executed in the run-time environment.
The behavior of this form can be more precisely understood in terms of a model of how compile-file processes forms in a file to be compiled. There are two processing modes, called “not-compile-time” (NCT) and “compile-time-too” (CTT).
Successive forms are read from the file by compile-file and processed in NCT mode; in this mode, compile-file arranges for forms to be evaluated only at load time and not at compile time. When compile-file is in CTT mode, forms are evaluated both at compile time and load time.
When compiling a top-level eval-when:
If the list is empty, then the s are discarded.
If the only :execute, in NCT mode the body forms will be discarded, but in CTT mode the body forms will be evaluated. is
If the only :compile-toplevel, or if the list consists only of :compile-toplevel and :execute, then, regardless of mode, the body forms will be evaluated in the dynamic execution context of the compiler. is
If the only :load-toplevel, then the compiler enters NCT mode and the body forms are processed as top level forms. is
If the :compile-toplevel, and :load-toplevel, then the compiler enters or continues in CTT mode, and the body forms are processed as top level forms. list includes both
If the :execute and :load-toplevel, then the body forms are processed as top level forms, but the mode does not change. list includes only
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 ()
()
‘(really-foo))
Right:
(defmacro ()
‘(eval-when (:compile-toplevel :execute
:load-toplevel)
()))
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 () (defun () (+ 3)))
might expand into
(defun ()
(progn
(eval-when (:compile-toplevel)
(compiler::notice-function-definition
’ ’()))
(eval-when (:execute :load-toplevel)
(setf (symbol-function ’)
#’(lambda () (+ 3))))))
which would be treated by the above rules the same as
(defun ()
(setf (symbol-function ’)
#’(lambda () (+ 3))))
when the definition of bar is not 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 ( )
(declare (ignore ))
(list ’ (read )))))
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 top level, 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 ’) to a function which returns 1.
(let (( 1))
(eval-when (:execute :load-toplevel
:compile-toplevel)
(setf (symbol-function ’)
#’(lambda () ))))
If this 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 ’) to a function which returns 2.
(eval-when (:execute :load-toplevel :compile-toplevel)
(let (( 2))
(eval-when (:execute :load-toplevel
:compile-toplevel)
(setf (symbol-function ’)
#’(lambda () )))))
If this 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 3.
(eval-when (:execute :load-toplevel :compile-toplevel)
(setf (symbol-function ’) #’(lambda () 3)))
to a function which returns
This always does nothing. It simply returns NIL.
(eval-when (:compile-toplevel)
(eval-when (:compile-toplevel)
(print ’)))
If this form occurs at top level of a file to be compiled,
(eval-when (:compile-toplevel)
(eval-when (:execute)
(print ’)))
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.
If this form occurs at top level of a file to be compiled,
(eval-when (:execute :load-toplevel)
(eval-when (:compile-toplevel)
(print ’)))
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.
SEE ALSO
compile-file(3cl)
AUTHOR and COPYRIGHT
Substantial portions of this page are taken from draft proposed American National Standard for Information Systems—Programming Language—Common Lisp, X3J13/94-101R, Version 15.17R, Fri 12-Aug-1994 6:35pm EDT; no copyright indicated.
Additional clarification and comments by Michael Marking <marking@tatanka.com>, http://www.tatanka.com/software/cl-manpages/; alternatively, https://github.com/wakinyantanka/cl-manpages/. Copyright 2017 Michael Marking as both an original and a derivative work.
Licensed under Creative Commons Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0).
This page last revised Sunday 26 February 2017.