* 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).