A required use of eval-when
is to ensure that functions which a macro depends on are available at the time the macro is compiled and is used. However, I can't think of an example that would demonstrate the consequences of not using eval-when
.
(defpackage :eval-when
(:use :cl))
(in-package :eval-when)
(defun util-fun (x) (* x x))
(defmacro needs-help (x) `(let ((a (util-fun ,x))) a))
;; use it in the same file
(defun use-the-macro (x) (needs-help x))
(use-the-macro 5)
If I understand correctly, the (defun util-fun ...)
should be wrapped with eval-when
.
EDIT: As you'll see from the Answer, there's a problem with this example: it doesn't actually call UTIL-FUN at compile time. This explains why no error is given, because it's not an error. But the question is still valid in that it highlights a new user's confusion.
However, from the REPL, no error or warning is issued during compilation, load or usage (SBCL 1.3.20):
; SLIME 2.19
CL-USER> (uiop:getcwd)
#P"/home/anticrisis/dev/common-lisp/eval-when/"
CL-USER> (compile-file "eval-when.lisp")
; compiling file "/home/anticrisis/dev/common-lisp/eval-when/eval-when.lisp" (written 14 AUG 2017 11:30:49 AM):
; compiling (DEFPACKAGE :EVAL-WHEN ...)
; compiling (IN-PACKAGE :EVAL-WHEN)
; compiling (DEFUN UTIL-FUN ...)
; compiling (DEFMACRO NEEDS-HELP ...)
; compiling (DEFUN USE-THE-MACRO ...)
; compiling (USE-THE-MACRO 5)
; /home/anticrisis/dev/common-lisp/eval-when/eval-when.fasl written
; compilation finished in 0:00:00.009
#P"/home/anticrisis/dev/common-lisp/eval-when/eval-when.fasl"
NIL
NIL
CL-USER> (in-package :eval-when)
#<PACKAGE "EVAL-WHEN">
EVAL-WHEN> (use-the-macro 3)
; Evaluation aborted on #<UNDEFINED-FUNCTION USE-THE-MACRO {10035E1103}>.
EVAL-WHEN> (needs-help 4)
; Evaluation aborted on #<UNDEFINED-FUNCTION UTIL-FUN {100387FE33}>.
EVAL-WHEN> (load "eval-when.lisp")
T
EVAL-WHEN> (use-the-macro 3)
9
EVAL-WHEN> (needs-help 4)
16
EVAL-WHEN>
Note that normally I use C-c C-k to eval and load a file to the repl, but here, I'm using the compile-file
and load
commands to demonstrate that no error occurs. (I do receive an error when I try to use the functions after they're compiled but before they are loaded, but that would occur with any unloaded code.)
There are prior questions and comments that relate to this:
This previous StackOverflow answer seems to very plainly say that any function which is used by a macro must be enclosed by the
eval-when
form, or loaded in a separate file.This comment from coredump is also very clear:
When the macro is expanded, any function that the macro calls must be defined. If you have a compilation unit which defines a macro, which calls functions, but you don't actually use the macro in the same compilation unit, you don't need eval-when. If however, you define an aux. function, a macro and want to use your macro right off after you define it, then the implementation might complain that the aux. function is unknown – coredump
Given that, why does my example not generate an error? Will my example fail under other scenarios? An example of the compile-time, load-time, or run-time error generated when failing to properly use eval-when
would be helpful to my understanding.
Thank you for your patience!