Common Lisp the Language, 2nd Edition


next up previous contents index
Next: Predicates Up: Top-Level Forms Previous: Declaring Global Variables

5.3.3. Control of Time of Evaluation

old_change_begin
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:

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.
old_change_end

change_begin
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:

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:

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.


change_end



next up previous contents index
Next: Predicates Up: Top-Level Forms Previous: Declaring Global Variables


AI.Repository@cs.cmu.edu