unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Simple macro question
       [not found] <20210503000712.l2wh2liwhg3jfjxy.ref@Ergus>
@ 2021-05-03  0:07 ` Ergus
  2021-05-03  1:29   ` Ergus
  2021-05-03  1:46   ` Stefan Monnier
  0 siblings, 2 replies; 5+ messages in thread
From: Ergus @ 2021-05-03  0:07 UTC (permalink / raw)
  To: help-gnu-emacs


Hi:

Playing with macros to generate function I got an problem I am not sure
how to solve or why is it an issue

In the following minimal code:

==============================

;;; test.el --- test editing -*- lexical-binding: t; -*-

;;; Commentary:

;;; Code:

(defvar test-commands-list '(A B C)
   "List of replaced functions.")

(defmacro test-def ()
   "Doc def."
   `(eval-and-compile ,@(mapcar (lambda (com) nil) test-commands-list)))

(test-def)

(provide 'test)
;;; test ends here

==============================

This code shows an error like:

Symbol’s value as variable is void: test-commands-list

in this line: (test-def)

I can't use test-commands-list either in this way or as an input if I
define the macro as:

(defmacro test-def (commands-list)
...

(test-def test-commands-list)

In this second case I get: wrong arguments sequencep test-commands-list

Is this intended?




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Simple macro question
  2021-05-03  0:07 ` Simple macro question Ergus
@ 2021-05-03  1:29   ` Ergus
  2021-05-03  1:46   ` Stefan Monnier
  1 sibling, 0 replies; 5+ messages in thread
From: Ergus @ 2021-05-03  1:29 UTC (permalink / raw)
  To: help-gnu-emacs

Equivalent code like this:

====================

;;; test.el --- test editing -*- lexical-binding: t; -*-

;;; Commentary:

;;; Code:

(defvar test-commands-list '(A B C)
   "List of replaced functions.")

(defun test-fun (com)
   "Testfun with COM."
   nil)

(defmacro test-def (thelist)
   "Doc def."
   `(progn ,@(mapcar #'test-fun thelist)))

(test-def (A B C))

(provide 'test)
;;; test ends here

============================

Says that: Symbol’s function definition is void: test-fun 


On Mon, May 03, 2021 at 02:07:12AM +0200, Ergus wrote:
>
>Hi:
>
>Playing with macros to generate function I got an problem I am not sure
>how to solve or why is it an issue
>
>In the following minimal code:
>
>==============================
>
>;;; test.el --- test editing -*- lexical-binding: t; -*-
>
>;;; Commentary:
>
>;;; Code:
>
>(defvar test-commands-list '(A B C)
>  "List of replaced functions.")
>
>(defmacro test-def ()
>  "Doc def."
>  `(eval-and-compile ,@(mapcar (lambda (com) nil) test-commands-list)))
>
>(test-def)
>
>(provide 'test)
>;;; test ends here
>
>==============================
>
>This code shows an error like:
>
>Symbol’s value as variable is void: test-commands-list
>
>in this line: (test-def)
>
>I can't use test-commands-list either in this way or as an input if I
>define the macro as:
>
>(defmacro test-def (commands-list)
>...
>
>(test-def test-commands-list)
>
>In this second case I get: wrong arguments sequencep test-commands-list
>
>Is this intended?
>
>



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Simple macro question
  2021-05-03  0:07 ` Simple macro question Ergus
  2021-05-03  1:29   ` Ergus
@ 2021-05-03  1:46   ` Stefan Monnier
  2021-05-03 11:32     ` Ergus
  1 sibling, 1 reply; 5+ messages in thread
From: Stefan Monnier @ 2021-05-03  1:46 UTC (permalink / raw)
  To: help-gnu-emacs

> (defvar test-commands-list '(A B C)
>   "List of replaced functions.")
> (defmacro test-def ()
>   "Doc def."
>   `(eval-and-compile ,@(mapcar (lambda (com) nil) test-commands-list)))
> (test-def)

[...]

> Symbol’s value as variable is void: test-commands-list

macro-expansion takes place during compilation.  During compilation, the
code is mostly translated, not evaluated, but macros are expanded.
So your `(test-def)` macro call is expanded which evaluates the code
inside `test-def` whereas the `(defvar ...)` code is not evaluated (it's
only translated into byte-code) and hence the var is not defined: it
will only be defined much later when the resulting byte-code is run.

One way to work around it is to place the `defvar` within an
`eval-and-compile`.

> (defmacro test-def (commands-list)
> ...
>
> (test-def test-commands-list)
>
> In this second case I get: wrong arguments sequencep test-commands-list
> Is this intended?

Yes: the argument to macros are the actual sexp written in the macro
call, not the result of their evaluation.  So your argument
`commands-list` will hold the symbol `test-commands-list` rather than
the list you were hoping to get.  You could use `symbol-value` to get
the content of that symbol as a variable, but then you'd be back to the
previous problem because the `defvar` has not been evaluated yet.


        Stefan




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Simple macro question
  2021-05-03  1:46   ` Stefan Monnier
@ 2021-05-03 11:32     ` Ergus
  2021-05-04 19:54       ` Stefan Monnier via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 5+ messages in thread
From: Ergus @ 2021-05-03 11:32 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

Hi Stefan:

Thanks for the reply.

IIUC then this code:

====================

;;; test.el --- test editing -*- lexical-binding: t; -*-

;;; Commentary:

;;; Code:

(defun test-fun (com)
   "Testfun with COM."
   nil)

(defmacro test-def (thelist)
   "Doc def."
   `(progn ,@(mapcar #'test-fun thelist)))

(test-def (A B C))

(provide 'test)
;;; test ends here

============================

Will require to put the test-fun inside an `eval-and-compile` too?
Because I am getting a similar error, this time test-fun is not defined.

I tried to use eval-and-compile in this case but the problem is that in
my real code test-fun calls another function (a minor mode) that needs
to be defined later (in the same file); and I get an error in that case
too that the minor-mode-function is not defined.

What's the canonical way to do that? use declare function? some trick
with the quoting? Put also the minor mode inside an eval-and-compile?

In case you are interested into why I came into this issues, here is the
code:

https://github.com/Ergus/composable.el/blob/master/composable.el

In the future I want to implement another version using the new
`repeat-mode` api, that will be cleaner, but at the moment it does not
makes sense as there is not any emacs release with the repeat api yet.

Thanks in advance,
Ergus


On Sun, May 02, 2021 at 09:46:30PM -0400, Stefan Monnier wrote:
>> (defvar test-commands-list '(A B C)
>>   "List of replaced functions.")
>> (defmacro test-def ()
>>   "Doc def."
>>   `(eval-and-compile ,@(mapcar (lambda (com) nil) test-commands-list)))
>> (test-def)
>
>[...]
>
>> Symbol’s value as variable is void: test-commands-list
>
>macro-expansion takes place during compilation.  During compilation, the
>code is mostly translated, not evaluated, but macros are expanded.
>So your `(test-def)` macro call is expanded which evaluates the code
>inside `test-def` whereas the `(defvar ...)` code is not evaluated (it's
>only translated into byte-code) and hence the var is not defined: it
>will only be defined much later when the resulting byte-code is run.
>
>One way to work around it is to place the `defvar` within an
>`eval-and-compile`.
>
>> (defmacro test-def (commands-list)
>> ...
>>
>> (test-def test-commands-list)
>>
>> In this second case I get: wrong arguments sequencep test-commands-list
>> Is this intended?
>
>Yes: the argument to macros are the actual sexp written in the macro
>call, not the result of their evaluation.  So your argument
>`commands-list` will hold the symbol `test-commands-list` rather than
>the list you were hoping to get.  You could use `symbol-value` to get
>the content of that symbol as a variable, but then you'd be back to the
>previous problem because the `defvar` has not been evaluated yet.
>
>
>        Stefan
>
>



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Simple macro question
  2021-05-03 11:32     ` Ergus
@ 2021-05-04 19:54       ` Stefan Monnier via Users list for the GNU Emacs text editor
  0 siblings, 0 replies; 5+ messages in thread
From: Stefan Monnier via Users list for the GNU Emacs text editor @ 2021-05-04 19:54 UTC (permalink / raw)
  To: help-gnu-emacs

> (defun test-fun (com)
>   "Testfun with COM."
>   nil)
>
> (defmacro test-def (thelist)
>   "Doc def."
>   `(progn ,@(mapcar #'test-fun thelist)))
>
> (test-def (A B C))
[...]
> Will require to put the test-fun inside an `eval-and-compile` too?

Yup: macro-expansion of `(test-def (A B C))` evaluates the body of
`test-def` and hence calls `test-fun`, but since this is done during
compilation, `test-fun` needs to be not just compiled but also defined.

> I tried to use eval-and-compile in this case but the problem is that in
> my real code test-fun calls another function (a minor mode) that needs
> to be defined later (in the same file);

It's hard to imagine a macro which needs to enable a minor mode during
its expansion.  Are you sure?


        Stefan




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-05-04 19:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20210503000712.l2wh2liwhg3jfjxy.ref@Ergus>
2021-05-03  0:07 ` Simple macro question Ergus
2021-05-03  1:29   ` Ergus
2021-05-03  1:46   ` Stefan Monnier
2021-05-03 11:32     ` Ergus
2021-05-04 19:54       ` Stefan Monnier via Users list for the GNU Emacs text editor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).