Special Operator eval-when

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. They are supported when \specref{eval-when} is a \term{top level form}, but their meaning is not defined elsewhere.

forms—an implicit progn.

results—the values of the forms if they are executed, or nil if they are not.

Description:

5.3.3 2 \specref{eval-when} specifies when a particular body of code is to be evaluated. 5.3.3 1.5 \specref{eval-when} allows pieces of code to be executed only at compile time, only in compiled code, or when interpreted but not compiled. If no \param{forms} are executed, \specref{eval-when} returns \nil. 5.3.3 3 \f{eval} specifies that the interpreter should process the body. \f{compile} specifies that the compiler should evaluate the body at compile time in the compilation context. \f{load} specifies that the compiler should arrange to evaluate the forms in the body when the compiled file containing the \specref{eval-when} form is \term{loaded}. The body of \specref{eval-when} is processed as an implicit \specref{progn}, but only in the allowed \param{situations}. The body of an eval-when form is processed as an implicit progn, but only in the situations listed. Each \param{situation} must be a symbol, either COMPILE, LOAD, or EVAL.

The file compilation section only describe processing by COMPILE-FILE. We must say something explicit here about EVAL and COMPILE. (The last paragraph from the eval-when cleanup has gotten lost.) I have rewritten this below to include the missing info. --sjl 5 Mar 92

The use of the \param{situations} \kwd{compile-toplevel} ({\tt compile}) and \kwd{load-toplevel} ({\tt load}) controls whether and when processing occurs for \term{top level forms}. The use of the situation \kwd{execute} ({\tt eval}) controls whether processing occurs for \term{non-top-level forms}. For a description of \specref{eval-when} processing, \seesection\FileCompilation.

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.

The \specref{eval-when} construct can be more precisely understood in terms of a model of how the file compiler, COMPILE-FILE, processes forms in a file to be compiled.

When successive \term{forms} are read from the file by \funref{compile-file}, these \term{top level forms} are normally processed in not-compile-time mode. There is one other mode, called compile-time-too mode, that is also used for processing \term{top level forms}. The \specref{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. When \funref{compile-file} encounters an \specref{eval-when} form, the \term{form} is handled according to the table in \thenextfigure. \boxfig \tabskip \dimen0 plus .5 fil \halign to \hsize {#\hfil\tabskip \dimen0 plus 1fil&#\hfil\tabskip \dimen0 plus .5 fil&#\hfil\tabskip \dimen0 plus 1fil&#\hfil\tabskip \dimen0 plus 1fil #\hfil \noalign{\vskip -9pt} \hfil{\bf A} & {\bf B} & {\bf C} & {\bf D}& {\bf Action} Yes & Yes &-- &-- &Process body in compile-time-too mode No &Yes &Yes &Yes &Process body in compile-time-too mode No &Yes &Yes &No &Process body in not-compile-time mode No &Yes &No &-- &Process body in not-compile-time mode Yes &No &-- &-- &Evaluate body No &No &Yes &Yes &Evaluate body No &No &Yes &No &do nothing No &No &No &-- &do nothing \noalign{\vskip -9pt} }} \caption{\specref{eval-when} processing} \endfig Column A indicates Column B indicates \kwd{load-toplevel} processing. Column C indicates {\tt :execute} processing. Column D indicates compile-time-too processing. Process body means to process the body (using the procedure outlined in this subsection) as an implicit toplevel \specref{progn}. Evaluate body means to evaluate the body \param{forms} as an \term{implicit progn} in the dynamic execution context \term{dynamic environment} of the compiler and in the \term{lexical environment} in which the \specref{eval-when} appears. For an \specref{eval-when} form that is not a \term{top level form}, if the \kwd{execute} situation is specified, the body of the \specref{eval-when} is treated as an \term{implicit progn}. Otherwise, the \specref{eval-when} form returns \nil. An \specref{eval-when} form is a \term{non-top-level form} if it is one of the following: in the interpreter, in \funref{compile}, or in \funref{compile-file} but not a \term{top level form}.

!!! Barmar: Redundant. (KMP: I'll have to think about that.) 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.

\specref{eval-when} is meaningful only as a \term{top level form}.

Examples:

!!! Are the EVAL-WHEN return values correct?? -kmp 29-Aug-91

Moon: Why isn't this compile toplevel? Maybe this example is not portable? It's an obfuscating example anyway. Delete it. \code (setq temp 3) \EV 3 (eval-when (:compile-toplevel) (setq temp 2)) \EV NIL temp \EV 3 (eval-when (:execute) (setq temp 2)) \EV 2 temp \EV 2 \endcode

5.3.3 10One 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)))

Affected By:

None.

Exceptional Situations:

None.

See Also:

compile-file, Section 3.2 (Compilation)

Notes:

The following effects are logical consequences of the definition of eval-when: