From: Thuna <thuna.cing@gmail.com>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: help-gnu-emacs@gnu.org
Subject: Re: `eval'ing form in the current lexical environment
Date: Mon, 08 Jul 2024 04:07:31 +0200 [thread overview]
Message-ID: <87y16c3acc.fsf@gmail.com> (raw)
In-Reply-To: <jwva5it6mwo.fsf-monnier+emacs@gnu.org> (Stefan Monnier via Users list for the's message of "Sun, 07 Jul 2024 15:16:30 -0400")
[ I appear to have forgotten to CC the list, sorry about that. Below's
what I have previously sent. Please only reply to this mail. ]
Hmm, I now realize that I misspoke in my original post. What is doing
this is not a macro but a function, so that was why I went to `eval'.
This form is being generated from within <processor> itself.
Now, your suggestion did bring up an interesting point for me in that I
could simply make a wrapper macro for this function and put that in, but
there does appear to be a problem with this approach in this specific
situation which... will be even more difficult to explain.
Below are two versions of me trying to explain the problem, one with
context and one with me attempting to reduce it down to the bare
essentials. I'll leave the former in in case I leave out some important
details in the latter, but I have to be honest: it is extremely
convoluted. Please only read it if the first explanation doesn't make
sense or if you wanted to take a look at the code and find yourself
confused as to what's happening in it.
--- Reduced down to essentials ---
The function (which I accidentally called a macro) we are talking about
is the <processor> itself, that is, it looks something like
(defun <processor> (form)
;; `(,head ,@args) == form
`(...
(if (macrop #',head)
(eval (<processor> `(,head ,@args)))
...
`(,head ,@argsyms))))
and there is a different macro which expands into the defun by doing
(defmacro (name lambda-list &rest body)
`(defun ,name ,lambda-list
,(<processor> `(progn ,@body))))
<processor> recursively expands and modifies FORM, and returns a version
of it which is "processed", and then the definition of NAME is set to be
that processed body.
All macros are expanded and processed, thus `(,head ,@args) above is
/necessarily/ a function call... that is, unless it is later redefined
as a macro.
The goal with (if (macrop #',head) ...) is to check for this exact case,
an in case it DID happen, fix it by processing the form again, calling
that processed version instead of what was supposed to happen.
This however can only during the runtime of NAME, because that is when
we are concerned with `head' being a macro, so the call to <processor>
must happen within NAME and not within the top-level <processor>.
Because we are calling <processor> during NAME, we obtain a form which
needs to be evaluated.
--- With context ---
Let me provide you with the actual code we are discussing. I intend to
bring this up in emacs-devel at some point anyways so hopefully it'll be
worth the read: https://git.sr.ht/~thuna/tcl-values
Quick rundown of what the code does: This is a library which simulates
true Common Lisp style multiple values. The way this is achieved by
having `cl-values' set a global variable which holds the values ONLY IF
an "expecting multiple values" flag is set. Any function which supports
multiple values must therefore ensure that this flag is suppressed (the
term used in the library for this is "sanitization") everywhere in the
code except for in the forms which are "returning" (in that, their
values is what the function will/may return).
While the function author can manually sanitize their function, this is
a cumbursome and tedious process so the function `tcl-values--sanitize'
is provided to sanitize any forms fed to it, which is called from
`tcl-defun' before defining the function. This is the nebulous
<processor> that we are talking about.
The specific branch in which this eval exists is the basic call to (func
arg1 arg2...). It's purpose is - in case `func' is later redefined as a
macro - to preserve the sanitization of the function by going through
the form and re-sanitize it. This needs to happen at runtime because
that's when we are attempting to detect if `func' was redefined or not.
Now, I looked into defining a macro which simply called
`tcl-values--sanitize', but this led to two problems:
1. This resolution happens at macroexpansion time, due to it being
`macroexpand-all'ed.
2. The branch which calls the macro is the same branch we feed into the
macro, thus the expansion of the macro contains exactly the same macro,
resulting in infinite recursion.
There *might* be some trick I can use to get rid of the second problem,
but I cannot think of one that would allow me to fix the first one,
unless I can somehow prevent macroexpand-all from expanding the
resulting macro.
next prev parent reply other threads:[~2024-07-08 2:07 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-07 18:55 `eval'ing form in the current lexical environment Thuna
2024-07-07 19:16 ` Stefan Monnier via Users list for the GNU Emacs text editor
2024-07-08 2:07 ` Thuna [this message]
2024-07-08 2:49 ` Stefan Monnier
2024-07-08 21:38 ` Thuna
2024-07-08 22:03 ` Stefan Monnier
2024-07-08 22:42 ` Thuna
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=87y16c3acc.fsf@gmail.com \
--to=thuna.cing@gmail.com \
--cc=help-gnu-emacs@gnu.org \
--cc=monnier@iro.umontreal.ca \
/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.