To reproduce: . emacs -Q . Type into *scratch: (add-hook 'mail-mode-hook #'(lambda () (setq flyspell-generic-check-word-p 'mail-mode-flyspell-verify))) . Evaluate the above expression with "C-x C-e" . Type into *scratch*: mail-mode-hook C-j . The result: ((closure (t) nil (setq flyspell-generic-check-word-p 'mail-mode-flyspell-verify))) Why are we present a simple lambda as a closure? why confuse users with something tricky instead of showing the lambda-form the user typed? In GNU Emacs 28.0.60 (build 156, i686-pc-mingw32) of 2021-11-23 built on HOME-C4E4A596F7 Repository revision: d791cd556d622accb935e4dd230023c485d1e07a Repository branch: emacs-28 Windowing system distributor 'Microsoft Corp.', version 5.1.2600 System Description: Microsoft Windows XP Service Pack 3 (v5.1.0.2600) Configured using: 'configure -C --prefix=/d/usr --with-wide-int --with-modules --enable-checking=yes,glyphs 'CFLAGS=-O0 -gdwarf-4 -g3'' Configured features: ACL GIF GMP GNUTLS HARFBUZZ JPEG JSON LCMS2 LIBXML2 MODULES NOTIFY W32NOTIFY PDUMPER PNG RSVG SOUND THREADS TIFF TOOLKIT_SCROLL_BARS XPM ZLIB Important settings: value of $LANG: ENU locale-coding-system: cp1255 Major mode: Lisp Interaction Minor modes in effect: tooltip-mode: t global-eldoc-mode: t eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t tool-bar-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t line-number-mode: t indent-tabs-mode: t transient-mark-mode: t Load-path shadows: None found. Features: (shadow sort mail-extr warnings emacsbug message rmc puny dired dired-loaddefs rfc822 mml mml-sec epa derived epg rfc6068 epg-config gnus-util rmail rmail-loaddefs auth-source cl-seq eieio eieio-core cl-macs eieio-loaddefs password-cache json map text-property-search time-date subr-x seq byte-opt gv bytecomp byte-compile cconv mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader cl-loaddefs cl-lib sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils dabbrev iso-transl tooltip eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel dos-w32 ls-lisp disp-table term/w32-win w32-win w32-vars term/common-win tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer cl-generic cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help simple abbrev obarray cl-preloaded nadvice button loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget hashtable-print-readable backquote threads w32notify w32 lcms2 multi-tty make-network-process emacs) Memory information: ((conses 16 57044 6934) (symbols 48 7874 2) (strings 16 21867 2892) (string-bytes 1 643712) (vectors 16 12975) (vector-slots 8 175379 9690) (floats 8 28 53) (intervals 40 316 141) (buffers 888 12))
Eli Zaretskii <eliz@gnu.org> writes: > . The result: > > ((closure (t) nil (setq flyspell-generic-check-word-p 'mail-mode-flyspell-verify))) > > Why are we present a simple lambda as a closure? why confuse users > with something tricky instead of showing the lambda-form the user > typed? I'm not sure what you're suggesting here. The key is bound to a closure, so that's what Emacs is showing. (If you switch lexical-binding off in *scratch* it won't be.) Do you mean that it shouldn't be a closure if the environment is just t? I'm not sure what the repercussions of that would be. Stefan? -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
> From: Lars Ingebrigtsen <larsi@gnus.org> > Cc: 52063@debbugs.gnu.org, Stefan Monnier <monnier@iro.umontreal.ca> > Date: Wed, 24 Nov 2021 08:35:30 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > > . The result: > > > > ((closure (t) nil (setq flyspell-generic-check-word-p 'mail-mode-flyspell-verify))) > > > > Why are we present a simple lambda as a closure? why confuse users > > with something tricky instead of showing the lambda-form the user > > typed? > > I'm not sure what you're suggesting here. The key is bound to a > closure Which key? I evaluated an add-hook expression. What I want to see is my lambda, the one I put in the hook. > (If you switch lexical-binding off in *scratch* it won't be.) I doubt that we want to tell users to switch off lexical-binding to see reasonably-formatted results from evaluation.
Eli Zaretskii <eliz@gnu.org> writes: >> I'm not sure what you're suggesting here. The key is bound to a >> closure > > Which key? I evaluated an add-hook expression. I meant the hook. > What I want to see is my lambda, the one I put in the hook. But you put a closure on your hook, not the lambda. (lambda () 1) => (closure (t) nil 1) -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: 52063@debbugs.gnu.org, monnier@iro.umontreal.ca
> Date: Wed, 24 Nov 2021 13:51:56 +0100
>
> > What I want to see is my lambda, the one I put in the hook.
>
> But you put a closure on your hook, not the lambda.
>
> (lambda () 1)
> => (closure (t) nil 1)
Where do you see something like the above in my recipe? The recipe
was:
(add-hook 'mail-mode-hook
#'(lambda () (setq flyspell-generic-check-word-p
'mail-mode-flyspell-verify)))
AFAIU, this adds a function to the hook. And the function is not a
constant 1, it has some code.
And please bear with me, I'm NOT teasing Emacs. I'm REALLY confused
here. It's a good-faith bug report about confusion. I added an
anonymous function to the hook, but Emacs says I added a closure.
WTF?
Btw, this comes from my ~/.emacs, so the problem is not limited to
evaluation in *scratch*.
Eli Zaretskii <eliz@gnu.org> writes: >> (lambda () 1) >> => (closure (t) nil 1) > > Where do you see something like the above in my recipe? The recipe > was: If you put (lambda () 1) into *scratch* and then `C-u C-x C-e' it'll spit put (closure (t) nil 1) Because that's what that form evaluates to in lexically bound buffers. `lambda' is no longer self-evaluating, and hasn't been for a few years. (But I guess it's pretty recent that *scratch* defaults to lexical.) And it's the same with (lambda () (setq flyspell-generic-check-word-p 'mail-mode-flyspell-verify)) of course. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: 52063@debbugs.gnu.org, monnier@iro.umontreal.ca
> Date: Wed, 24 Nov 2021 14:31:22 +0100
>
> If you put
>
> (lambda () 1)
>
> into *scratch* and then `C-u C-x C-e' it'll spit put
>
> (closure (t) nil 1)
>
> Because that's what that form evaluates to in lexically bound buffers.
> `lambda' is no longer self-evaluating, and hasn't been for a few years.
>
> (But I guess it's pretty recent that *scratch* defaults to lexical.)
>
> And it's the same with
>
> (lambda ()
> (setq flyspell-generic-check-word-p
> 'mail-mode-flyspell-verify))
>
> of course.
I'm asking why we are doing this. IT IS CONFUSING!!!
Eli Zaretskii <eliz@gnu.org> writes: > I'm asking why we are doing this. IT IS CONFUSING!!! I think it would be more confusing to have some lambdas be lambdas and some be closures. But it would certainly be possible to make the closures that have no bindings into lambdas again. Take this example: (setq foo (lambda (a) (lambda () (+ a 2)))) (funcall (funcall foo 1)) If we eval-ed `foo' to a lambda here, the funcall would signal an error. That is, I don't find it confusing -- I find it to be consistent. Somebody that works in a lexically-bound Lisp has to deal with closures sooner or later, so special-casing some bits seems counter-productive to me. But perhaps others have other opinions here? -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
> But perhaps others have other opinions here?
Compile your code and the problem goes away (because you'll never see
(lambda ...) or (closure ...) values, they'll all be
byte-code-functions instead ;-)
Stefan
On 24/11/2021 16:38 +0200, Eli Zaretskii wrote:
>> From: Lars Ingebrigtsen <larsi@gnus.org>
>> Cc: 52063@debbugs.gnu.org, monnier@iro.umontreal.ca
>> Date: Wed, 24 Nov 2021 14:31:22 +0100
>>
>> If you put
>>
>> (lambda () 1)
>>
>> into *scratch* and then `C-u C-x C-e' it'll spit put
>>
>> (closure (t) nil 1)
>>
>> Because that's what that form evaluates to in lexically bound buffers.
>> `lambda' is no longer self-evaluating, and hasn't been for a few years.
>>
>> (But I guess it's pretty recent that *scratch* defaults to lexical.)
>>
>> And it's the same with
>>
>> (lambda ()
>> (setq flyspell-generic-check-word-p
>> 'mail-mode-flyspell-verify))
>>
>> of course.
>
> I'm asking why we are doing this. IT IS CONFUSING!!!
But you're creating normal lambda here, and under lex-bind it will
become a closure, to keep its lexical environment together with it. In
your case there's nothing in lex environment, so that's it.
I just realized that I don't have lex-binding turned on in .emacs, and
because of that my customized hooks look "good", but I wonder: what is
the recommended binding mode for .emacs? Dynamic or lexical? With
lexical, all customizations would start to look as your example.
> what is the recommended binding mode for .emacs? Dynamic or lexical?
`lexical-binding` should be enabled everywhere.
The non-lexical-binding dialect will be phased out.
Stefan
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>, 52063@debbugs.gnu.org
> Date: Wed, 24 Nov 2021 11:33:31 -0500
>
> > But perhaps others have other opinions here?
>
> Compile your code and the problem goes away (because you'll never see
> (lambda ...) or (closure ...) values, they'll all be
> byte-code-functions instead ;-)
I don't want to compile my .emacs.
Any other words of wisdom before I write this off as another
annoyance of lexical-binding, and take care to disable that wherever I
can?
> From: Filipp Gunbin <fgunbin@fastmail.fm> > Cc: Lars Ingebrigtsen <larsi@gnus.org>, 52063@debbugs.gnu.org, > monnier@iro.umontreal.ca > Date: Wed, 24 Nov 2021 19:40:16 +0300 > > But you're creating normal lambda here, and under lex-bind it will > become a closure, to keep its lexical environment together with it. So how do I get my lambda back, in the lexical-binding environment? > I just realized that I don't have lex-binding turned on in .emacs, and > because of that my customized hooks look "good", but I wonder: what is > the recommended binding mode for .emacs? Dynamic or lexical? With > lexical, all customizations would start to look as your example. That's how I discovered this nit.
>> > But perhaps others have other opinions here?
>> Compile your code and the problem goes away (because you'll never see
>> (lambda ...) or (closure ...) values, they'll all be
>> byte-code-functions instead ;-)
> I don't want to compile my .emacs.
> Any other words of wisdom before I write this off as another annoyance
> of lexical-binding, and take care to disable that wherever I can?
The other word of wisdom is:
Don't add lambdas to hook. Always name those functions.
That's good advice regardless of lexical/dynamic scoping.
Stefan
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: larsi@gnus.org, 52063@debbugs.gnu.org
> Date: Wed, 24 Nov 2021 12:19:51 -0500
>
> >> > But perhaps others have other opinions here?
> >> Compile your code and the problem goes away (because you'll never see
> >> (lambda ...) or (closure ...) values, they'll all be
> >> byte-code-functions instead ;-)
> > I don't want to compile my .emacs.
> > Any other words of wisdom before I write this off as another annoyance
> > of lexical-binding, and take care to disable that wherever I can?
>
> The other word of wisdom is:
> Don't add lambdas to hook. Always name those functions.
So this issue is specific to hooks? I thought add-hook is just a
fancy way of consing a list, but you seem to say that it has some side
effects that other constructs don't?
IOW, would manually consing a list with a lambda-function produce the
same results, or would it leave the lambda-function intact?
On 24/11/2021 11:54 -0500, Stefan Monnier wrote:
>> what is the recommended binding mode for .emacs? Dynamic or lexical?
>
> `lexical-binding` should be enabled everywhere.
> The non-lexical-binding dialect will be phased out.
Yes, I know that eventually it'll be phased out, but then perhaps issues
such as this need special attention..
>> >> > But perhaps others have other opinions here? >> >> Compile your code and the problem goes away (because you'll never see >> >> (lambda ...) or (closure ...) values, they'll all be >> >> byte-code-functions instead ;-) >> > I don't want to compile my .emacs. >> > Any other words of wisdom before I write this off as another annoyance >> > of lexical-binding, and take care to disable that wherever I can? >> The other word of wisdom is: >> Don't add lambdas to hook. Always name those functions. > So this issue is specific to hooks? No, but in 99% of the cases you won't actually *see* a function value (unless you specifically go looking for it, e.g. with `symbol-function`). One of the cases where you are more likely to see one is if you look at the value of a hook. > I thought add-hook is just a fancy way of consing a list, It is. > but you seem to say that it has some side effects that other > constructs don't? Not really, no. > IOW, would manually consing a list with a lambda-function produce the > same results, Yes. > or would it leave the lambda-function intact? No. A *value* of the form (lambda ARGS . BODY) is a (non-compiled) dynamically-scoped function. Non-compiled statically-scoped function values use the form (closure ENV ARGS . BODY...). So you'll only get a value of the form (lambda ARGS . BODY) if you use the dynamically scoped dialect of ELisp (or if you manually create such a list, e.g. with '(lambda ...) or `(lambda ...) or (list 'lambda ...), etc...). Stefan
Filipp Gunbin [2021-11-24 21:18:43] wrote:
> On 24/11/2021 11:54 -0500, Stefan Monnier wrote:
>>> what is the recommended binding mode for .emacs? Dynamic or lexical?
>> `lexical-binding` should be enabled everywhere.
>> The non-lexical-binding dialect will be phased out.
> Yes, I know that eventually it'll be phased out, but then perhaps issues
> such as this need special attention..
Indeed, but I'm not sure what we can do about it.
From where I sit, the problem is one of habit.
Stefan
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>, Lars Ingebrigtsen <larsi@gnus.org>,
> 52063@debbugs.gnu.org
> Date: Wed, 24 Nov 2021 14:08:55 -0500
>
> >From where I sit, the problem is one of habit.
There's nothing wrong with habits, and there's no reason to fight
habits of others, even if you don't share them.
>> >From where I sit, the problem is one of habit.
> There's nothing wrong with habits, and there's no reason to fight
> habits of others, even if you don't share them.
What I'm saying is that you are annoyed by the (closure ...) thingy
mostly because you're used to seeing (lambda ...) rather than because
there's an actual problem with the (closure ...) itself.
IOW if it had always behaved that way, you wouldn't be bothered by it.
If I had my way, we'd never see any (lambda ...) value nor any (closure
...) value, but we'd instead see things more like #<function ...> or
maybe #[function ...] ;-)
Stefan
> From: Stefan Monnier <monnier@iro.umontreal.ca> > Cc: larsi@gnus.org, 52063@debbugs.gnu.org > Date: Wed, 24 Nov 2021 14:06:37 -0500 > > > So this issue is specific to hooks? > > No, but in 99% of the cases you won't actually *see* a function value > (unless you specifically go looking for it, e.g. with `symbol-function`). We also have gobs of variables that are not hooks, which accept function values. And we also have menu items and mode-line constructs that sometimes use anonymous functions. And timer functions. And process filter and sentinel functions. And that's just 5 sec of thinking where one could meet them. > So you'll only get a value of the form (lambda ARGS . BODY) if you use > the dynamically scoped dialect of ELisp (or if you manually create such > a list, e.g. with '(lambda ...) or `(lambda ...) or (list 'lambda ...), > etc...). So I guess the warning about quoting lambdas with ' instead of #' is actually misleading people into getting these closures instead of the lambdas they might expect? Because that is how this started for me: during startup Emacs said: .emacs: Warning: (lambda nil \.\.\.) quoted with ' rather than with #' So why do we emit those warnings for Lisp code evaluated from a file that doesn't have lexical-binding setting in it? If it were not for this warning, I'd have never tried using #', and thus would have never bumped into this curiosity.
> From: Stefan Monnier <monnier@iro.umontreal.ca> > Cc: fgunbin@fastmail.fm, larsi@gnus.org, 52063@debbugs.gnu.org > Date: Wed, 24 Nov 2021 14:46:04 -0500 > > >> >From where I sit, the problem is one of habit. > > There's nothing wrong with habits, and there's no reason to fight > > habits of others, even if you don't share them. > > What I'm saying is that you are annoyed by the (closure ...) thingy > mostly because you're used to seeing (lambda ...) rather than because > there's an actual problem with the (closure ...) itself. And that is strange because?... I want to see the code I wrote, not some strange transformation of it. > IOW if it had always behaved that way, you wouldn't be bothered by it. This kind of arguments lead nowhere useful. It smells of disrespect to dissenting opinions, which I'm sure you didn't intend. I'm annoyed by this misfeature. If it means nothing to you and others, so be it.
>> No, but in 99% of the cases you won't actually *see* a function value >> (unless you specifically go looking for it, e.g. with `symbol-function`). > We also have gobs of variables that are not hooks, which accept > function values. Indeed, tho I think there are a few more such hooks and at least I have looked at hook values a lot more often than I have looked at <foo>-function values. > And we also have menu items and mode-line constructs > that sometimes use anonymous functions. I think it's very rare for a user to look at those objects. > And timer functions. I can't remember the last time I looked at such a value. And given the extra info attached to it, it's not very legible so I don't think people are affected very much by a change in the actual function representation there. > And process filter and sentinel functions. Same here: you will often set them, but very rarely will you actually look at their value. > And that's just 5 sec of thinking where one could meet them. Indeed, there are many more places. >> So you'll only get a value of the form (lambda ARGS . BODY) if you use >> the dynamically scoped dialect of ELisp (or if you manually create such >> a list, e.g. with '(lambda ...) or `(lambda ...) or (list 'lambda ...), >> etc...). > > So I guess the warning about quoting lambdas with ' instead of #' is > actually misleading people into getting these closures instead of the > lambdas they might expect? A value (lambda ...) is fundamentally a list. The rest of the system (e.g. the byte-compiler, flymake, ...) can't know if you intend to use this list as a function, so it can't really look inside to compile its body, warn you about typos in its body, or uses of obsolete vars/functions, etc... > So why do we emit those warnings for Lisp code evaluated from a file > that doesn't have lexical-binding setting in it? Those warnings predate the introduction of lexical scoping, indeed. They're mostly there so you don't mistakenly write code which the byte-compiler can't compile (and which `flymake` can't analyze to give you further feedback about issues in that code). It's all about the difference between code and data ;-) Stefan
> From: Stefan Monnier <monnier@iro.umontreal.ca> > Cc: larsi@gnus.org, 52063@debbugs.gnu.org > Date: Wed, 24 Nov 2021 15:08:38 -0500 > > > And we also have menu items and mode-line constructs > > that sometimes use anonymous functions. > > I think it's very rare for a user to look at those objects. > > > And timer functions. > > I can't remember the last time I looked at such a value. And given the > extra info attached to it, it's not very legible so I don't think people > are affected very much by a change in the actual function > representation there. > > > And process filter and sentinel functions. > > Same here: you will often set them, but very rarely will you actually > look at their value. I look at the values to make sure they are what I expect. It's normal in Emacs to do that, isn't it? > > So I guess the warning about quoting lambdas with ' instead of #' is > > actually misleading people into getting these closures instead of the > > lambdas they might expect? > > A value (lambda ...) is fundamentally a list. The rest of the system > (e.g. the byte-compiler, flymake, ...) can't know if you intend to use > this list as a function, so it can't really look inside to compile its > body, warn you about typos in its body, or uses of obsolete > vars/functions, etc... I'm talking about evaluation, not about byte-compilation. This happened when Emacs was processing my init file. > It's all about the difference between code and data ;-) What difference? I always thought that in Emacs Lisp there's no such difference. Does lexical-binding change that as well?
Am Mi., 24. Nov. 2021 um 20:17 Uhr schrieb Stefan Monnier via Bug
reports for GNU Emacs, the Swiss army knife of text editors
<bug-gnu-emacs@gnu.org>:
>
> Filipp Gunbin [2021-11-24 21:18:43] wrote:
> > On 24/11/2021 11:54 -0500, Stefan Monnier wrote:
> >>> what is the recommended binding mode for .emacs? Dynamic or lexical?
> >> `lexical-binding` should be enabled everywhere.
> >> The non-lexical-binding dialect will be phased out.
> > Yes, I know that eventually it'll be phased out, but then perhaps issues
> > such as this need special attention..
>
> Indeed, but I'm not sure what we can do about it.
Maybe, once the non-lexical dialect is gone, we can make (closure (t)
(lambda ...)) identical to (lambda ...) and then prefer the latter
again.
>> What I'm saying is that you are annoyed by the (closure ...) thingy >> mostly because you're used to seeing (lambda ...) rather than because >> there's an actual problem with the (closure ...) itself. > And that is strange because?... Because a function value is fundamentally something very different from the text of the code from which it came. E.g. just `read`ing the object will have lost info such as comments or choice between ?a and 97, then macroexpansion will change the code further, and with lexical scoping the need to capture the environment means that the function values need to be completed with the captured environment. > I want to see the code I wrote, not > some strange transformation of it. Given all the info lost between the source code and the actual function value (it's even worse if the code gets compiled), I think the better way to do that is to try and keep a reference to the source. We currently don't do that, but we should. >> IOW if it had always behaved that way, you wouldn't be bothered by it. > This kind of arguments lead nowhere useful. It smells of disrespect > to dissenting opinions, which I'm sure you didn't intend. No, it's just a guess, based on experience in other languages. > I'm annoyed by this misfeature. If it means nothing to you and > others, so be it. I fully understand desire to see function values printed as much as possible as their original source code, but it's hard to reconcile this with the needs of clean semantics, efficient execution, good code analysis, ... Stefan
On Wed, 24 Nov 2021 at 17:09, Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors <bug-gnu-emacs@gnu.org> wrote: > > I think it's very rare for a user to look at those objects. That's a matter of taste. For me one of the charms of Emacs is that most objects have internal representations that I can inspect and understand. Compiled functions are not like that, but when I need to inspect a byte-compiled function foo-bletch that was defined in the file foo.elc I can usually run (load "foo.el"), and this overrides the byte-compiled foo-bletch with a non-byte-compiled version. Cheers, Eduardo Ochs http://angg.twu.net/#eev http://angg.twu.net/emacsconf2021.html
>> Indeed, but I'm not sure what we can do about it.
> Maybe, once the non-lexical dialect is gone, we can make (closure (t)
> (lambda ...)) identical to (lambda ...) and then prefer the latter
> again.
That's sufficiently far into the future that i have no idea whether
it'll be a good idea ;-)
Stefan
>> > So I guess the warning about quoting lambdas with ' instead of #' is >> > actually misleading people into getting these closures instead of the >> > lambdas they might expect? >> >> A value (lambda ...) is fundamentally a list. The rest of the system >> (e.g. the byte-compiler, flymake, ...) can't know if you intend to use >> this list as a function, so it can't really look inside to compile its >> body, warn you about typos in its body, or uses of obsolete >> vars/functions, etc... > > I'm talking about evaluation, not about byte-compilation. > This happened when Emacs was processing my init file. I'm tlking neither specifically about evaluation nor compilation, I'm just talking about the meaning of '(lambda ...) which prevents our tools from looking at the code inside of it because those tools can't tell whether it's supposed to contain source code or just arbitrary data. >> It's all about the difference between code and data ;-) > What difference? I always thought that in Emacs Lisp there's no such > difference. I think saying that "code is data" is misunderstood. All it means is that code is exposed as a kind of data, e.g. via macros. But obviously not every piece of data is a valid and usable piece of code. And when ELisp knows that a specific piece of data is actually a piece of code, it can take the liberty to manipulate it accordingly under the assumption that it's "somewhat opaque" and that the only thing we're going to do with it is evaluate/run it rather than manipulate it with, say, `car/cdr`. E.g. when we load a .el file containing: (defun foo (xs) (dolist (x xs) (when x (message "%s" x)))) the `symbol-function` cell of `foo` will not contain (dolist (x xs) (when x (message "%s" x))) > Does lexical-binding change that as well? It makes the difference a bit bigger. Stefan
On 11/24/2021 12:14 PM, Eli Zaretskii wrote:
> I look at the values to make sure they are what I expect. It's normal
> in Emacs to do that, isn't it?
I think in cases like that, it's useful to see the closure, since that's
information that can help the user debug a problem. For example, if I
have something like the following, it's helpful to see information about
the closure:
(let ((foo 1))
(add-hook 'prog-mode-hook (lambda () (setq foo 1))))
In that case, the value of prog-mode-hook is:
((closure ((foo . 1) t) nil (setq foo 1)))
This is a contrived example, but similar sorts of things crop up in the
real world. If the above example were significantly more complex (e.g.
the `let' and the `add-hook' were in different functions), I might not
realize that `foo' was lexically-bound unless I looked at the value of
`prog-mode-hook' and saw the closure.
As such, I think the current behavior is better than simply showing what
the user typed, i.e. "(lambda () ...)". That doesn't show the variables
bound by the closure. However, the specific representation of the
closure object could use some improvement. For example, I don't know
what purpose the `t' and `nil' serve, although I'm sure both are useful
to experts in some situations. Is there a way to represent all this
information in a way that's easy for users to understand without
expecting them to know the details of how closures are implemented in Emacs?
>> I'm annoyed by this misfeature. If it means nothing to you and others, >> so be it. > > I fully understand desire to see function values printed as much as > possible as their original source code, but it's hard to reconcile this > with the needs of clean semantics, efficient execution, good code > analysis, ... > AFAIU, the fundamental question here is: is "(closure (t) args body)" different in any way from "(lambda args body)"? If not, is there a good reason to use a "(closure (t)" instead of a "(lambda"? FWIW, I'm running an Emacs with the following patch right now, which apparently breaks a couple of edebug tests in make check. Apart from that, it seems that it doesn't change anything in the way Emacs behaves. diff --git a/src/eval.c b/src/eval.c index 94ad060773..5d02cabaf4 100644 --- a/src/eval.c +++ b/src/eval.c @@ -564,6 +564,8 @@ DEFUN ("function", Ffunction, Sfunction, 1, UNEVALLED, 0, xsignal2 (Qwrong_number_of_arguments, Qfunction, Flength (args)); if (!NILP (Vinternal_interpreter_environment) + && !(EQ (Fcar (Vinternal_interpreter_environment), Qt) && + NILP (Fcdr (Vinternal_interpreter_environment))) && CONSP (quoted) && EQ (XCAR (quoted), Qlambda)) { /* This is a lambda expression within a lexical environment;
On 11/24/2021 2:33 PM, Jim Porter wrote:
> This is a contrived example, but similar sorts of things crop up in the
> real world. If the above example were significantly more complex (e.g.
> the `let' and the `add-hook' were in different functions), I might not
> realize that `foo' was lexically-bound unless I looked at the value of
> `prog-mode-hook' and saw the closure.
Sorry, this part isn't correct (at least, I don't think it is): "(e.g.
the `let' and the `add-hook' were in different functions)". So just
ignore that bit. :)
Nevertheless, it could be that the bound variables in a closure aren't
what you'd expect, so I still think it's useful to see them somehow.
On 24/11/2021 22:37 +0000, Gregory Heytings wrote:
>>> I'm annoyed by this misfeature. If it means nothing to you and others,
>>> so be it.
>>
>> I fully understand desire to see function values printed as much as
>> possible as their original source code, but it's hard to reconcile this
>> with the needs of clean semantics, efficient execution, good code
>> analysis, ...
>>
>
> AFAIU, the fundamental question here is: is "(closure (t) args body)"
> different in any way from "(lambda args body)"? If not, is there a good
> reason to use a "(closure (t)" instead of a "(lambda"?
>
> FWIW, I'm running an Emacs with the following patch right now, which
> apparently breaks a couple of edebug tests in make check. Apart from
> that, it seems that it doesn't change anything in the way Emacs behaves.
>
> [..]
Please let's not do that. We may need the context, that the function
originated as a closure, later for some reasons. Rather, I like what
Stefan said, that we should keep the reference to the source.
On 24/11/2021 21:16 +0100, Philipp Stephani wrote:
> Am Mi., 24. Nov. 2021 um 20:17 Uhr schrieb Stefan Monnier via Bug
> reports for GNU Emacs, the Swiss army knife of text editors
> <bug-gnu-emacs@gnu.org>:
>>
>> Filipp Gunbin [2021-11-24 21:18:43] wrote:
>> > On 24/11/2021 11:54 -0500, Stefan Monnier wrote:
>> >>> what is the recommended binding mode for .emacs? Dynamic or lexical?
>> >> `lexical-binding` should be enabled everywhere.
>> >> The non-lexical-binding dialect will be phased out.
>> > Yes, I know that eventually it'll be phased out, but then perhaps issues
>> > such as this need special attention..
>>
>> Indeed, but I'm not sure what we can do about it.
>
> Maybe, once the non-lexical dialect is gone, we can make (closure (t)
> (lambda ...)) identical to (lambda ...) and then prefer the latter
> again.
Or maybe we could just _print_ the closure objects in such a special
way that it's more pleasant to read, especially when there's actually
empty lexical environment.
Gregory Heytings <gregory@heytings.org> writes:
> AFAIU, the fundamental question here is: is "(closure (t) args body)"
> different in any way from "(lambda args body)"? If not, is there a
> good reason to use a "(closure (t)" instead of a "(lambda"?
This is my question, too. But not only: any anonymous function that
doesn't reference any part of its environment could (?) also be
represented as a lambda list. With other words: only "real" closures
would be represented as (closure ...). That would make inspection of
values and things like debugging easier.
Michael.
Michael Heerdegen <michael_heerdegen@web.de> writes: > Gregory Heytings <gregory@heytings.org> writes: > >> AFAIU, the fundamental question here is: is "(closure (t) args body)" >> different in any way from "(lambda args body)"? If not, is there a >> good reason to use a "(closure (t)" instead of a "(lambda"? > > This is my question, too. But not only: any anonymous function that > doesn't reference any part of its environment could (?) also be > represented as a lambda list. With other words: only "real" closures > would be represented as (closure ...). That would make inspection of > values and things like debugging easier. A closure has lexical binding inside itself, though, which lambdas do not have. So checking for an empty lexical environment isn't sufficient to decide whether to try to convert back to a lambda or not -- you have to do some deep inspection. (See code snippet that demonstrates the issue in an earlier post of mine.) -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
Filipp Gunbin <fgunbin@fastmail.fm> writes: > Or maybe we could just _print_ the closure objects in such a special > way that it's more pleasant to read, especially when there's actually > empty lexical environment. (pp-emacs-lisp-code (lambda () (setq foo bar) (setq foo bar))) => (closure (t) nil (setq foo bar) (setq foo bar)) Slightly less confusing, but perhaps it should be (closure (t) nil (setq foo bar) (setq foo bar)) Depends on the length of the lexical list, though: (pp-emacs-lisp-code (let ((bar 1)) (lambda (f) (setq foo bar) (setq foo bar)))) => (closure ((bar . 1) t) (f) (setq foo bar) (setq foo bar)) can be unwieldy if the list is long. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
Lars Ingebrigtsen <larsi@gnus.org> writes:
> A closure has lexical binding inside itself, though, which lambdas do
> not have. [...] (See code snippet that demonstrates the issue in an
> earlier post of mine.)
Oh - indeed. Then those function values have fundamentally different
semantics when funcalled, and it's good that they are represented
differently.
My guess would be that the decision "can be translated into a lambda" in
the general case is either expensive or not even decidable.
Michael.
>
> A closure has lexical binding inside itself, though, which lambdas do
> not have. So checking for an empty lexical environment isn't sufficient
> to decide whether to try to convert back to a lambda or not -- you have
> to do some deep inspection. (See code snippet that demonstrates the
> issue in an earlier post of mine.)
>
Indeed, that was the counter-example I tried to find. I should read your
posts more carefully ;-) My initial feeling, that (closure (t) args body)
is not equivalent to (lambda args body), was correct after all.
> Depends on the length of the lexical list, though:
>
> (pp-emacs-lisp-code
> (let ((bar 1))
> (lambda (f) (setq foo bar) (setq foo bar))))
> =>
> (closure ((bar . 1) t) (f)
> (setq foo bar)
> (setq foo bar))
>
> can be unwieldy if the list is long.
[ Taking a step back and ignoring practical concerns like whether it's
easy to implement efficiently. ]
We could have something like:
(let ((foo 1)
(bar 2)
(baz 5))
(lambda (x) (+ x bar)))
return an object like
(closure (x) ((bar . 2))
(+ x bar))
instead of the current
(closure ((baz . 5) (bar . 2) (foo . 1) t) (x)
(+ x bar))
IOW, the final `t` can be dispensed with, we could swap the arglist and
the captured environment, and we could filter the environment to only
include variables which are actually used inside the function.
Stefan
On 11/25/2021 11:07 AM, Stefan Monnier via Bug reports for GNU Emacs,
the Swiss army knife of text editors wrote:
> IOW, the final `t` can be dispensed with, we could swap the arglist and
> the captured environment, and we could filter the environment to only
> include variables which are actually used inside the function.
It might be nice to print an empty arglist as "()" instead of "nil" too.
While both of those are equivalent, I think "()" is more idiomatic when
showing an arglist. Currently we have:
(lambda () (setq foo 1))
;; => (closure (t) nil (setq foo 1))
In that case, since there's no captured variables and no args, it might
be nicer to show it as:
(closure () () (setq foo 1))
Or even:
(closure () (setq foo 1))
Stefan Monnier <monnier@iro.umontreal.ca> writes: > We could have something like: > > (let ((foo 1) > (bar 2) > (baz 5)) > (lambda (x) (+ x bar))) > > return an object like > > (closure (x) ((bar . 2)) > (+ x bar)) > > instead of the current > > (closure ((baz . 5) (bar . 2) (foo . 1) t) (x) > (+ x bar)) That does seem a lot more readable (and makes the similarities to `lambda' more obvious. Could we go one further and do (closure (x) (environment ((bar . 2))) (+ x bar)) or something like that? And in that case, we could just say even say that (lambda (x) (declare (environment ((bar . 2)))) (+ x bar)) is how to represent this. 😀 (I.e., a `lambda' with a `declare environment' is a closure.) (Which would also mean that we'd have to allow `declare' in lambdas, which I think we should anyway.) -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
Jim Porter <jporterbugs@gmail.com> writes: > It might be nice to print an empty arglist as "()" instead of "nil" > too. While both of those are equivalent, I think "()" is more > idiomatic when showing an arglist. Currently we have: > > (lambda () (setq foo 1)) > ;; => (closure (t) nil (setq foo 1)) The printer used here is a general Lisp printer, and doesn't know anything about the semantics. (And I don't think we can change that.) But Emacs 29 has a language-aware pp variant, which does what you suggest: (lambda () 'foo) => (closure (t) nil 'foo) (pp-emacs-lisp-code '(closure (t) nil 'foo)) => (closure (t) () 'foo) -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
> or something like that? And in that case, we could just say even say that
>
> (lambda (x)
> (declare (environment ((bar . 2))))
> (+ x bar))
>
> is how to represent this. 😀 (I.e., a `lambda' with a `declare
> environment' is a closure.)
>
> (Which would also mean that we'd have to allow `declare' in lambdas,
> which I think we should anyway.)
I sense a bit of confusion: we're talking about the runtime representation
of function values: those never occur in source code.
Stefan
Stefan Monnier <monnier@iro.umontreal.ca> writes: > I sense a bit of confusion: we're talking about the runtime representation > of function values: those never occur in source code. Yes, but we're able to funcall those runtime representations. So that doesn't really make much of a difference here, I think? -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
Lars Ingebrigtsen <larsi@gnus.org> writes: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >> I sense a bit of confusion: we're talking about the runtime representation >> of function values: those never occur in source code. > > Yes, but we're able to funcall those runtime representations. So that > doesn't really make much of a difference here, I think? (That is -- the point of all this is to make the printed representation of the runtime representation more recognisable (and usable) as source code, even if it'll never appear in nature.) -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
>>> I sense a bit of confusion: we're talking about the runtime representation >>> of function values: those never occur in source code. >> Yes, but we're able to funcall those runtime representations. I'd hope so: that's what runtime representation of functions are for. >> So that doesn't really make much of a difference here, I think? > (That is -- the point of all this is to make the printed representation > of the runtime representation more recognisable (and usable) as source > code, even if it'll never appear in nature.) My objection was to: (Which would also mean that we'd have to allow `declare' in lambdas, which I think we should anyway.) -- Stefan
Stefan Monnier <monnier@iro.umontreal.ca> writes: > My objection was to: > > (Which would also mean that we'd have to allow `declare' in lambdas, > which I think we should anyway.) You don't think we should allow `declare' in lambdas? It'd allow us to implement things like "named lambdas" more easily. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
Lars Ingebrigtsen [2021-11-26 16:00:43] wrote:
> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>> My objection was to:
>>
>> (Which would also mean that we'd have to allow `declare' in lambdas,
>> which I think we should anyway.)
>
> You don't think we should allow `declare' in lambdas? It'd allow us to
> implement things like "named lambdas" more easily.
I object to linking the two issues because one is about the `lambda`
expressions in source code and the other is about runtime representation
of function values and the two are fundamentally distinct (e.g. most
runtime function values are compiled).
Stefan
Stefan Monnier <monnier@iro.umontreal.ca> writes: > I object to linking the two issues because one is about the `lambda` > expressions in source code and the other is about runtime representation > of function values and the two are fundamentally distinct (e.g. most > runtime function values are compiled). I agree in principle, but the original confusion here was that the runtime representation didn't resemble the source code sufficiently. You suggested making the runtime representation more similar to the source code, and I suggested making it even more similar. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
Lars Ingebrigtsen [2021-11-27 15:17:39] wrote:
> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>> I object to linking the two issues because one is about the `lambda`
>> expressions in source code and the other is about runtime representation
>> of function values and the two are fundamentally distinct (e.g. most
>> runtime function values are compiled).
>
> I agree in principle, but the original confusion here was that the
> runtime representation didn't resemble the source code sufficiently.
> You suggested making the runtime representation more similar to the
> source code, and I suggested making it even more similar.
I'm OK with making the printed representation similar to the
source code. But when that is in turn used to motivate changes to the
source code, I think it's gone too far.
It's hard enough to design good source syntax without such constraints.
Also, I think it's good if the source syntax is a bit different from the
function value syntax: we want the two to be *similar* so the function
value feels familiar and can intuitively be understood, but we also want
to make it clear that we're looking at something
fundamentally different.
That's why I'd favor a representation of the form #[...] or #<...> or ...
Stefan
Stefan Monnier <monnier@iro.umontreal.ca> writes: > I'm OK with making the printed representation similar to the > source code. But when that is in turn used to motivate changes to the > source code, I think it's gone too far. > It's hard enough to design good source syntax without such constraints. I'm not sure I follow you -- I don't think this would mean changing any source code? But, yes, it would mean that people might be tempted to write actual code like (lambda () (declare (lexical-binding (foo . 1))) ...) but people might be tempted to do the same with `closure' forms, and that doesn't seem to be happening. My point is that if we're extending the `lambda' syntax, we might as well do it in a way that allows further easy expansions in the future. > Also, I think it's good if the source syntax is a bit different from the > function value syntax: we want the two to be *similar* so the function > value feels familiar and can intuitively be understood, but we also want > to make it clear that we're looking at something > fundamentally different. > > That's why I'd favor a representation of the form #[...] or #<...> or ... Hm, right... I think I'm in favour of demystifying, not further mystifying things for the users. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no
> My point is that if we're extending the `lambda' syntax, we might as > well do it in a way that allows further easy expansions in the future. And my point is that we're not discussing the syntax of `lambda` but the representation of function values. [ I agree with the above, BTW. I just don't think it is relevant to the problem at hand. ] >> Also, I think it's good if the source syntax is a bit different from the >> function value syntax: we want the two to be *similar* so the function >> value feels familiar and can intuitively be understood, but we also want >> to make it clear that we're looking at something >> fundamentally different. >> That's why I'd favor a representation of the form #[...] or #<...> or ... > Hm, right... I think I'm in favour of demystifying, not further > mystifying things for the users. Currently the vast majority of functions in Emacs's heap (i.e. function *values*) get printed either as a symbol or as #[...] or as #<subr...>. The (lambda ...) and (closure ...) cases are in the minority and I think it would be good to try and eliminate these cases as much as possible (we'll probably have to keep supporting it for backward compatibility, but we can stop generating them ourselves). Stefan
Lars Ingebrigtsen <larsi@gnus.org> writes:
> But, yes, it would mean that people might be tempted to write actual
> code like
>
> (lambda ()
> (declare (lexical-binding (foo . 1)))
> ...)
>
> but people might be tempted to do the same with `closure' forms, and
> that doesn't seem to be happening.
But the above idea is a step in the direction to make closures look even
more like code. Declarations are a coding thing. I think we would
regret that very soon. Kind of "what happened to my lambda, who added
these declarations?" (if that sounded ironically: this is not intended).
Michael.
Michael Heerdegen <michael_heerdegen@web.de> writes: > But the above idea is a step in the direction to make closures look even > more like code. Declarations are a coding thing. I think we would > regret that very soon. Kind of "what happened to my lambda, who added > these declarations?" (if that sounded ironically: this is not intended). Heh; that's a good point. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no