ToC | DocOverview | CGDoc | RelNotes | Index | PermutedIndex
| Allegro CL

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

© Franz Inc. All Rights Reserved - File last updated 2022-07-25