Эти возможности позволяют вам писать код, который будет вычисляться во время компиляции программы.
Эта форма указывает, что body должен вычисляться как при компиляции содержащего его кода, так и при его выполнении (скомпилированного или нет).
Похожего результата можно добиться, поместив body в отдельный файл и обратившись к этому файлу с помощью require. Этот способ предпочтительнее, когда body велик. Фактически require автоматически действует как eval-and-compile — пакет загружается как при компиляции, так и при выполнении.
autoload также фактически является eval-and-compile. Он распознаётся при компиляции, поэтому использование такой функции не вызывает предупреждений «не известно, что определена».
Большинство применений eval-and-compile довольно сложны.
Если у макроса есть вспомогательная функция для построения его результата, и этот макрос используется как локально, так и за пределами пакета, то eval-and-compile следует использовать, чтобы вспомогательная функция была доступна как при компиляции, так и впоследствии при выполнении.
Если функции определяются программно (скажем, с помощью fset), то eval-and-compile можно использовать, чтобы это выполнялось как во время компиляции, так и во время выполнения, чтобы вызовы этих функций проверялись (а предупреждения «не известно, что определена» подавлялись).
Эта форма указывает, что body должен вычисляться во время компиляции, но не при загрузке скомпилированной программы. Результат вычисления компилятором становится константой, которая появляется в скомпилированной программе. Если вы загружаете исходный файл, а не компилируете его, body вычисляется обычным образом.
Если у вас есть константа, для получения которой требуются некоторые вычисления, eval-when-compile может выполнить их во время компиляции. Например,
(defvar gauss-schoolboy-problem (eval-when-compile (apply #'+ (number-sequence 1 100))))
Если вы используете другой пакет, но нуждаетесь только в макросах из него (байт-компилятор раскроет их), то eval-when-compile можно использовать для его загрузки во время компиляции, но не при выполнении. Например,
(eval-when-compile (require 'my-macro-package))
То же самое относится к макросам и функциям defsubst, определённым локально и используемым только внутри файла. Они нужны для компиляции файла, но в большинстве случаев не требуются для выполнения скомпилированного файла. Например,
(eval-when-compile
(unless (fboundp 'some-new-thing)
(defmacro some-new-thing ()
(compatibility code))))
Это часто полезно для кода, который служит лишь запасным вариантом для совместимости с другими версиями Emacs.
Замечание для Common Lisp: На верхнем уровне eval-when-compile аналогичен идиоме Common Lisp (eval-when (compile eval) …). В других местах ридер-макрос Common Lisp ‘#.’ (но не при интерпретации) ближе по смыслу к тому, что делает eval-when-compile.