emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Using the content of a dynamic variable in a macro


From: Basil Contovounesios
Subject: Re: Using the content of a dynamic variable in a macro
Date: Mon, 27 Feb 2023 19:03:15 +0000
User-agent: Gnus/5.13 (Gnus v5.13)

Damien Cassou [2023-02-25 09:34 +0100] wrote:

> I'm wondering why the code below works but won't compile.
>
> foo.el:
>   (defvar foo-var '((message "hello world")))
>   
>   (defmacro foo-macro ()
>     `(progn
>        ,@foo-var))
>   
>   (defun foo-fun ()
>     (foo-macro))
>
>
> $ emacs --batch -l foo.el --eval '(foo-fun)'
> hello world
>
> $ emacs --batch --eval '(find-file "foo.el")' --eval 
> '(emacs-lisp-byte-compile)'
> In toplevel form:
> foo.el:32:1: Error: Symbol’s value as variable is void: foo-var
>
> Why isn't the compiler aware of the foo-var variable?

[ Lynn and Tomas have already answered this, but just to put it all
  together and cite the manual: ]

The reason is that the byte-compiler generally avoids evaluating the
source it is compiling, with the exception of forms like 'require' and
'eval-and-compile'.

But at the same time, the byte-compiler needs to expand all macro calls.

So in foo-fun it tries to expand the call to foo-macro, which inspects
the value of foo-var, but foo-var's initial value has not yet been
evaluated (by the byte-compiler, that is).

To load a definition into the byte-compiler, it needs to be placed in
either eval-when-compile (for things specific to the byte-compilation
process, such as loading macro definitions from another library),
eval-and-compile (for things that are needed at load time as well, such
as defining a missing function or modifying load-path), or a separate
library that is then 'require'd.

'require' is probably the least likely to confuse the reader, but is
often overkill.  In the example foo-var is only ever used during
macroexpansion, so eval-when-compile is okay - the variable will be
completely omitted from the .elc, but no load/run time code uses it
anyway.

But IME this is a rare use-case for global variables, which are more
often also present in the resulting .elc - so eval-and-compile may be
safer or more appropriate depending on the context.  It is also closer
to 'require'.

This stuff is briefly touched on under "(elisp) Compilation Functions":

--8<---------------cut here---------------start------------->8---
   Be careful when writing macro calls in files that you intend to
byte-compile.  Since macro calls are expanded when they are compiled,
the macros need to be loaded into Emacs or the byte compiler will not do
the right thing.  The usual way to handle this is with ‘require’ forms
which specify the files containing the needed macro definitions (see
Named Features).  Normally, the byte compiler does not evaluate the
code that it is compiling, but it handles ‘require’ forms specially, by
loading the specified libraries.  To avoid loading the macro definition
files when someone _runs_ the compiled program, write
‘eval-when-compile’ around the ‘require’ calls (see Eval During
Compile).  For more details, see Compiling Macros.
--8<---------------cut here---------------end--------------->8---

HTH,

-- 
Basil



reply via email to

[Prev in Thread] Current Thread [Next in Thread]