all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Basil Contovounesios <contovob@tcd.ie>
To: Damien Cassou <damien@cassou.me>
Cc: emacs-devel@gnu.org
Subject: Re: Using the content of a dynamic variable in a macro
Date: Mon, 27 Feb 2023 19:03:15 +0000	[thread overview]
Message-ID: <87lekj53t8.fsf@tcd.ie> (raw)
In-Reply-To: <87o7pi9m9s.fsf@cassou.me> (Damien Cassou's message of "Sat, 25 Feb 2023 09:34:07 +0100")

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



  parent reply	other threads:[~2023-02-27 19:03 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-25  8:34 Using the content of a dynamic variable in a macro Damien Cassou
2023-02-25  9:38 ` Eli Zaretskii
2023-02-25  9:43   ` Damien Cassou
2023-02-25 12:32     ` Lynn Winebarger
2023-02-27  3:24       ` Richard Stallman
2023-02-27 19:05         ` Basil Contovounesios
2023-02-28  2:44           ` Lynn Winebarger
2023-02-25  9:40 ` tomas
2023-02-27 19:03 ` Basil Contovounesios [this message]
  -- strict thread matches above, loose matches on Subject: below --
2023-02-24  6:31 Damien Cassou
2023-02-26 11:47 ` Michael Heerdegen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87lekj53t8.fsf@tcd.ie \
    --to=contovob@tcd.ie \
    --cc=damien@cassou.me \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.