9

Common idiom to workaround macro expansion or resolve warning about undefined variables during byte-compilation:

(eval-when-compile
  (require 'cl-lib))

But this require ... compiled into .elc file! I found that cl-eval-when have proper semantic (according to name).

Normally we don't need for require as site file and package.el

For example I want to byte-compile my .emacs which uses some external macros, but silently pass through if there are no such package:

(cl-eval-when 'compile
  (condition-case err
      (require 'w3m-util)
    (error (byte-compile-warn "Failed by: %S" err))))
(w3m-util-DEPENDENT-CODE ...)

Another way to do this is:

(ignore-error
   (require 'w3m-util)
   (w3m-util-DEPENDENT-CODE ...))

But now we are not a top level form...

Do I properly fill that eval-when-compile name do something that is not expected from its name?

Drew
  • 75,699
  • 9
  • 109
  • 225
gavenkoa
  • 3,352
  • 19
  • 36
  • FWIW, the latter two snippets do not have the same behavior. The former does not protect `w3m-DEPENDENT-CODE` from a missing `w3m-util`. – Drew Oct 13 '15 at 15:27
  • `(when (require 'w3m-util nil t) (w3m-util-DEPENDENT-CODE...))` – Drew Oct 13 '15 at 15:29
  • `(when (require 'w3m-util nil t) ...)` is nice idiom! But I try to make perfect `.emacs` file, not a library. So have in mind delayed (on-request) code loading with help of auto-loading. For this reason I extensively use `eval-after-load`, asked `require` needs only to make byte-compilation success with macro expansion. – gavenkoa Oct 14 '15 at 21:20

2 Answers2

10

Did you ask Emacs what eval-when-compile is supposed to do?

C-h f eval-when-compile tells you that it evaluates the arg also at load time:

eval-when-compile is a Lisp macro in `byte-run.el'.

(eval-when-compile &rest BODY)

Like ‘progn’, but evaluates the body at compile time if you’re compiling.
Thus, the result of the body appears to the compiler as a quoted
constant.  In interpreted code, this is entirely equivalent to
‘progn’, except that the value of the expression may be (but is
not necessarily) computed at load time if eager macro expansion
is enabled.

It says that if interpreted it is like progn. And it explicitly repeats this.

A function or macro name seldom reflects the behavior perfectly. But in this case it sounds like you are looking for a different behavior, which might be called eval-only-when-compile.

Drew
  • 75,699
  • 9
  • 109
  • 225
5

To evaluate code only on compilation stage use eval-when macros which is dated by RMS in 1993-07-30.

cl-eval-when appeared in 2012-06-03 from Stefan Monnier and it is not available for Emacs 22.x (if you care, I do).

For example you like to get rid of Warning: assignment to free variable in:

(setq auto-revert-interval 2)

just add above that line:

(eval-when 'compile (require 'autorevert))

Note that this is useful only for byte compilation of .emacs file. If you develop a library you should do require or split library file into separate and load only required features.

gavenkoa
  • 3,352
  • 19
  • 36
  • To avoid variable warnings, you just need `(defvar auto-revert-interval)` – npostavs Apr 02 '16 at 22:59
  • 1
    I use `defvar` solution in many cases but also look for *stronger* solution. I can mistype name or package can remove definition and compilation checker would be silent in such cases. – gavenkoa Apr 04 '16 at 19:03
  • 1
    `Symbol’s function definition is void: eval-when`. Btw, adding a "only require on compile" code to a library is exactly what I trying to do. There is one function that is only used in python-mode. Doing a `(require 'python)` always just because of that single function results in ≈110ms of excess delay when the package gets loaded, that's ridiculous. – Hi-Angel Jan 09 '23 at 18:31
  • I think `eval-when` is supposed to be a `cl-eval-when`, from `cl-lib` or `cl-macs`. That works. – Hi-Angel Jan 09 '23 at 19:15