GNU bug report logs - #66756
30.0.50; [PATCH] Improve discussion of 'let' in Elisp Introduction manual

Previous Next

Package: emacs;

Reported by: Jim Porter <jporterbugs <at> gmail.com>

Date: Thu, 26 Oct 2023 05:56:01 UTC

Severity: normal

Tags: patch

Found in version 30.0.50

Fixed in version 29.2

Done: Jim Porter <jporterbugs <at> gmail.com>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 66756 in the body.
You can then email your comments to 66756 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Thu, 26 Oct 2023 05:56:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Jim Porter <jporterbugs <at> gmail.com>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Thu, 26 Oct 2023 05:56:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: bug-gnu-emacs <at> gnu.org
Subject: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp Introduction
 manual
Date: Wed, 25 Oct 2023 22:54:25 -0700
[Message part 1 (text/plain, inline)]
(Spun out from bug#66706. My previous message below.)

On 10/25/2023 8:48 PM, Jim Porter wrote:
> On 10/25/2023 6:19 PM, Jim Porter wrote:
>> I'll start with a patch here then. I think this is also a prime spot
>> to add an example or two that would actually show lexical binding in
>> action (i.e. a sample where the code would do something different
>> under dynamic binding).
>
> Here's a first attempt. I'm not sure I'm entirely happy with it (the
> digression into setting 'lexical-binding' to 't' is a bit disruptive),
> but hopefully it's an improvement. Of course, we can keep adjusting this
> further as needed.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Thu, 26 Oct 2023 18:32:02 GMT) Full text and rfc822 format available.

Message #8 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: 66756 <at> debbugs.gnu.org, eliz <at> gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Thu, 26 Oct 2023 11:30:46 -0700
[Message part 1 (text/plain, inline)]
On 10/26/2023 12:09 AM, Eli Zaretskii wrote:
> Thanks.
>
> The challenge in updating the Lisp Introduction manual is to try to
> keep its informal and reader-friendly style as much as possible.  It
> is not just another ELisp Reference manual!  So please try to keep
> that in mind when you write the text, and in particular try not to
> modify the existing text that is still accurate -- it was written by a
> master, and each word there counts, even if it looks at first sight as
> not important.

Ok, here's a second attempt. I've tried to avoid changing anything that 
I don't think is truly necessary. I did alter a bit of the original 
wording to emphasize that under lexical binding, 'let' isn't about time, 
but about place. For example, that's why I changed this:

> This is like understanding that whenever your host refers to ``the house'', he means his house, not yours.

to this:

> This is like understanding that in your host's home, whenever he refers to ``the house'', he means his house, not yours.

My previous concern about the "lexical binding" digression still applies 
though. However, I'm not sure how to get around that at present; if we 
want to talk about lexical binding in the manual, we need to get users 
to enable it, so I think it's unavoidable that we at least mention it. I 
tried to introduce the jargon as gently as I could (by first introducing 
the term "binding" on its own before mentioning "lexical/dynamic 
binding"), but it's still a bit intimidating. On the positive side, when 
lexical binding is the default, we could remove that entire digression.

There's also an argument that the example I added is in the wrong spot, 
since we haven't actually introduced the 'let' syntax yet. However, I 
personally find the example to be pretty useful since it shows off one 
of the key differences between lexical and dynamic binding, and helps 
show one of the boundaries of the 'let' form's scope. I myself tend to 
learn best by seeing examples of that sort. Fixing the order so we 
introduce the syntax first would require more extensive changes to this 
section...
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 29 Oct 2023 16:39:01 GMT) Full text and rfc822 format available.

Message #11 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50;
 [PATCH] Improve discussion of 'let' in Elisp Introduction manual
Date: Sun, 29 Oct 2023 12:38:18 -0400
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > This is like understanding that in your host's home, whenever he refers to ``the house'', he means his house, not yours.

That seems good enough to me.

  > My previous concern about the "lexical binding" digression still applies 
  > though. However, I'm not sure how to get around that at present; if we 
  > want to talk about lexical binding in the manual, we need to get users 
  > to enable it, so I think it's unavoidable that we at least mention it. 

I think that the lexical/dynamic scope distinction is sufficiently
important that this manual should explain it, whether or not hiding it
is simply impossible.

However, tehre are lots of simple Lisp functions for which lexical
vs dynamic maks no diffeence.  For example,

(defun square (x)
  (* x x))

So perhaps it is possible for the first few sections to use examples
which work the same in lexical mode and dynamic mode, THEN show an
example for which it does make a difference as a way to explain the
two modes.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 29 Oct 2023 17:20:01 GMT) Full text and rfc822 format available.

Message #14 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Drew Adams <drew.adams <at> oracle.com>
To: "rms <at> gnu.org" <rms <at> gnu.org>, Jim Porter <jporterbugs <at> gmail.com>
Cc: "eliz <at> gnu.org" <eliz <at> gnu.org>,
 "66756 <at> debbugs.gnu.org" <66756 <at> debbugs.gnu.org>
Subject: RE: [External] : bug#66756: 30.0.50; [PATCH] Improve discussion of
 'let' in Elisp Introduction manual
Date: Sun, 29 Oct 2023 17:18:31 +0000
> I think that the lexical/dynamic scope distinction is sufficiently
> important that this manual should explain it, whether or not hiding it
> is simply impossible.
> 
> However, tehre are lots of simple Lisp functions for which lexical
> vs dynamic maks no diffeence.  For example, (defun square (x) (* x x))
> 
> So perhaps it is possible for the first few sections to use examples
> which work the same in lexical mode and dynamic mode, THEN show an
> example for which it does make a difference as a way to explain the
> two modes.

+1.


Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sat, 04 Nov 2023 08:29:01 GMT) Full text and rfc822 format available.

Message #17 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Richard Stallman <rms <at> gnu.org>
Cc: Jim Porter <jporterbugs <at> gmail.com>, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sat, 04 Nov 2023 10:27:51 +0200
> Date: Thu, 26 Oct 2023 11:30:46 -0700
> From: Jim Porter <jporterbugs <at> gmail.com>
> 
> On 10/26/2023 12:09 AM, Eli Zaretskii wrote:
>  > Thanks.
>  >
>  > The challenge in updating the Lisp Introduction manual is to try to
>  > keep its informal and reader-friendly style as much as possible.  It
>  > is not just another ELisp Reference manual!  So please try to keep
>  > that in mind when you write the text, and in particular try not to
>  > modify the existing text that is still accurate -- it was written by a
>  > master, and each word there counts, even if it looks at first sight as
>  > not important.
> 
> Ok, here's a second attempt. I've tried to avoid changing anything that 
> I don't think is truly necessary. I did alter a bit of the original 
> wording to emphasize that under lexical binding, 'let' isn't about time, 
> but about place. For example, that's why I changed this:
> 
> > This is like understanding that whenever your host refers to ``the house'', he means his house, not yours.
> 
> to this:
> 
> > This is like understanding that in your host's home, whenever he refers to ``the house'', he means his house, not yours.
> 
> My previous concern about the "lexical binding" digression still applies 
> though. However, I'm not sure how to get around that at present; if we 
> want to talk about lexical binding in the manual, we need to get users 
> to enable it, so I think it's unavoidable that we at least mention it. I 
> tried to introduce the jargon as gently as I could (by first introducing 
> the term "binding" on its own before mentioning "lexical/dynamic 
> binding"), but it's still a bit intimidating. On the positive side, when 
> lexical binding is the default, we could remove that entire digression.
> 
> There's also an argument that the example I added is in the wrong spot, 
> since we haven't actually introduced the 'let' syntax yet. However, I 
> personally find the example to be pretty useful since it shows off one 
> of the key differences between lexical and dynamic binding, and helps 
> show one of the boundaries of the 'let' form's scope. I myself tend to 
> learn best by seeing examples of that sort. Fixing the order so we 
> introduce the syntax first would require more extensive changes to this 
> section...

Richard, could you please review these changes?

> From 12847e0d59b2de3791efa090addc0169e713e6d1 Mon Sep 17 00:00:00 2001
> From: Jim Porter <jporterbugs <at> gmail.com>
> Date: Wed, 25 Oct 2023 20:43:57 -0700
> Subject: [PATCH] Introduce 'let' using lexical binding in the Lisp
>  Introduction
> 
> * doc/lispintro/emacs-lisp-intro.texi (Prevent confusion): Rework the
> explanation to discuss how things work under lexical binding
> (including how to enable it).
> ---
>  doc/lispintro/emacs-lisp-intro.texi | 67 ++++++++++++++++++++++-------
>  1 file changed, 51 insertions(+), 16 deletions(-)
> 
> diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi
> index fce7583fe91..e805833f979 100644
> --- a/doc/lispintro/emacs-lisp-intro.texi
> +++ b/doc/lispintro/emacs-lisp-intro.texi
> @@ -3602,24 +3602,59 @@ Prevent confusion
>  @cindex @samp{variable, local}, defined
>  The @code{let} special form prevents confusion.  @code{let} creates a
>  name for a @dfn{local variable} that overshadows any use of the same
> -name outside the @code{let} expression.  This is like understanding
> -that whenever your host refers to ``the house'', he means his house, not
> -yours.  (Symbols used in argument lists work the same way.
> +name outside the @code{let} expression (in computer science jargon, we
> +call this ``binding'' the variable).  This is like understanding that
> +in your host's home, whenever he refers to ``the house'', he means his
> +house, not yours.  (Symbols used in argument lists work the same way.
>  @xref{defun, , The @code{defun} Macro}.)
>  
> -Local variables created by a @code{let} expression retain their value
> -@emph{only} within the @code{let} expression itself (and within
> -expressions called within the @code{let} expression); the local
> -variables have no effect outside the @code{let} expression.
> -
> -Another way to think about @code{let} is that it is like a @code{setq}
> -that is temporary and local.  The values set by @code{let} are
> -automatically undone when the @code{let} is finished.  The setting
> -only affects expressions that are inside the bounds of the @code{let}
> -expression.  In computer science jargon, we would say the binding of
> -a symbol is visible only in functions called in the @code{let} form;
> -in Emacs Lisp, the default scoping is dynamic, not lexical.  (The
> -non-default lexical binding is not discussed in this manual.)
> +@cindex lexical binding
> +@cindex binding, lexical
> +@cindex dynamic binding
> +@cindex binding, dynamic
> +Before we begin discussing @code{let} in detail, we must first mention
> +an important note.  For historical reasons, Emacs Lisp uses a form of
> +variable binding called ``dynamic binding''.  However, this manual
> +will discuss the preferred form of binding, called ``lexical binding''
> +(if you have programmed in other languages before, you're likely
> +already familiar with how lexical binding behaves).  In order to use
> +lexical binding, you should add something like this to the first line
> +of your Emacs Lisp file:
> +
> +@example
> +;;; -*- lexical-binding: t -*-
> +@end example
> +
> +For more information about this, @pxref{Selecting Lisp Dialect, , ,
> +elisp, The Emacs Lisp Reference Manual}.
> +
> +With that out of the way, we can get back to discussing @code{let}.
> +Another way to think about @code{let} is that it defines a place in
> +your code where the variables you named have their own local meaning.
> +Outside of the @code{let} body, they have another meaning (or they may
> +not be defined at all).
> +
> +This means that inside the @code{let} body, calling @code{setq}
> +for a variable named by the @code{let} expression will set the value
> +of the @emph{local} variable of that name.  This also means that
> +outside of the @code{let} body, calling @code{setq} for a variable
> +named by the @code{let} expression will @emph{not} affect that local
> +variable.
> +
> +For example, if you call a function inside of a @code{let}
> +body, that function's body would be unable to ``see'' (or modify) the
> +value of a local variable from the @code{let} expression:
> +
> +@example
> +(setq x 1)
> +
> +(defun getx ()
> +  x)
> +
> +(let ((x 2))
> +  (get-x))
> +     @result{} 1
> +@end example
>  
>  @code{let} can create more than one variable at once.  Also,
>  @code{let} gives each variable it creates an initial value, either a
> -- 
> 2.25.1
> 




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sat, 04 Nov 2023 16:46:02 GMT) Full text and rfc822 format available.

Message #20 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>, Richard Stallman <rms <at> gnu.org>
Cc: 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sat, 4 Nov 2023 09:44:48 -0700
On 11/4/2023 1:27 AM, Eli Zaretskii wrote:
> Richard, could you please review these changes?

I see that there are already some good suggestions for how to improve my 
patch, so I'll try to work on that this weekend.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Mon, 06 Nov 2023 02:31:01 GMT) Full text and rfc822 format available.

Message #23 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50;
 [PATCH] Improve discussion of 'let' in Elisp Introduction manual
Date: Sun, 05 Nov 2023 21:29:29 -0500
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

This change is overall a step forward.  Thanks for working on it.

A few specific parts of the new text could use a little cleaning up;
some of those parts are in the current version also.

    +``scope'').  @code{let} creates a name for a @dfn{local variable} that
    +overshadows any use of the same name outside the @code{let} expression
    +(we call this ``binding'' the variable).

The word "overshadows" seems stramge here.  The usual term is "shadows",
and I don't see that "overshadows" adds any clarity.

  >   For historical reasons, Emacs Lisp uses a form of
  > +variable binding called ``dynamic binding''.

This should say "by default", because it isn't always so.  For
instance, if you specify lexical binding, then Emacs Lisp does not use
dynamic binding, except for variables marked special.

  > +lexical binding, you should add something like this to the first line

Delete "something like".



-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Mon, 06 Nov 2023 02:31:02 GMT) Full text and rfc822 format available.

Message #26 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50;
 [PATCH] Improve discussion of 'let' in Elisp Introduction manual
Date: Sun, 05 Nov 2023 21:29:30 -0500
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > +The @code{let} special form provides a way to confine your variables
  > +to a particular section of your code (in computer science jargon, a
  > +``scope'').  @code{let} creates a name for a @dfn{local variable} that
  > +overshadows any use of the same name outside the @code{let} expression
  > +(we call this ``binding'' the variable).  This prevents any accidental
  > +usage of these variables outside of the @code{let} expression.

This is one of several reasons to use `let'.

Others are

* To compute a value once and use it more than once.

* To create a loop index variable.

* For special variables, to bind them si as to control the behavior
of other code.

Should all of them be mentioned in this node?  I am not sure;
that is a pedagogical question.  But this node shouldn't assert
that one reason is the only reason.


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sat, 18 Nov 2023 02:10:01 GMT) Full text and rfc822 format available.

Message #29 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Fri, 17 Nov 2023 18:09:20 -0800
[Message part 1 (text/plain, inline)]
On 10/29/2023 9:38 AM, Richard Stallman wrote:
> So perhaps it is possible for the first few sections to use examples
> which work the same in lexical mode and dynamic mode, THEN show an
> example for which it does make a difference as a way to explain the
> two modes.

It took a bit longer for me to get back to this than I had hoped, but 
here's an updated patch. I've added a new subsection to the end that 
describes lexical vs dynamic binding, and tried to keep the "let 
Prevents Confusion" section as similar in spirit as I could to the 
original, while still updating the parts that change under lexical binding.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 19 Nov 2023 03:40:01 GMT) Full text and rfc822 format available.

Message #32 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sat, 18 Nov 2023 22:39:03 -0500
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

I think your changes are good.

  > +parts a ``scope'').  For historical reasons, Emacs Lisp uses a form of
  > +variable binding called ``dynamic binding'' by default.  However, in
  > +this manual, we discuss the preferred form of binding, called
  > +``lexical binding'' (if you have programmed in other languages before,
  > +you're likely already familiar with how lexical binding behaves).  In
  > +order to use lexical binding in a program, you should add this to the
  > +first line of your Emacs Lisp file:
  > +
  > +@example
  > +;;; -*- lexical-binding: t -*-
  > +@end example
  > +
  > +For more information about this, @pxref{Selecting Lisp Dialect, , ,
  > +elisp, The Emacs Lisp Reference Manual}.

Do we want to change the default some day to lexical binding:?  If so,
we should say so somewhere in this manual -- perhaps here, perhaps
elsewhere,

  > +If we instead change @code{lexical-binding} to have a value of
  > +@code{nil}, we will get a different result here.

"Get a different result" is vague -- it would be clearer if it said
concretely what will happen.

I suggest you show the dynamci situation in the same way you show the lexical
situation.  That will help people compare the two.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 19 Nov 2023 05:26:01 GMT) Full text and rfc822 format available.

Message #35 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sat, 18 Nov 2023 21:25:42 -0800
[Message part 1 (text/plain, inline)]
On 11/18/2023 7:39 PM, Richard Stallman wrote:
>    > +parts a ``scope'').  For historical reasons, Emacs Lisp uses a form of
>    > +variable binding called ``dynamic binding'' by default.  However, in
>    > +this manual, we discuss the preferred form of binding, called
>    > +``lexical binding'' (if you have programmed in other languages before,
>    > +you're likely already familiar with how lexical binding behaves).  In
>    > +order to use lexical binding in a program, you should add this to the
>    > +first line of your Emacs Lisp file:
>    > +
>    > +@example
>    > +;;; -*- lexical-binding: t -*-
>    > +@end example
>    > +
>    > +For more information about this, @pxref{Selecting Lisp Dialect, , ,
>    > +elisp, The Emacs Lisp Reference Manual}.
> 
> Do we want to change the default some day to lexical binding:?  If so,
> we should say so somewhere in this manual -- perhaps here, perhaps
> elsewhere,

I believe that's the goal, yes. I've added a note that the maintainers 
eventually plan on making lexical binding the default.

>    > +If we instead change @code{lexical-binding} to have a value of
>    > +@code{nil}, we will get a different result here.
> 
> "Get a different result" is vague -- it would be clearer if it said
> concretely what will happen.
> 
> I suggest you show the dynamci situation in the same way you show the lexical
> situation.  That will help people compare the two.

Done. I've also expanded the prose explanation at the end in order to 
re-emphasize the differences between the two.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 19 Nov 2023 05:31:02 GMT) Full text and rfc822 format available.

Message #38 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sat, 18 Nov 2023 21:30:11 -0800
[Message part 1 (text/plain, inline)]
On 11/18/2023 9:25 PM, Jim Porter wrote:
> I believe that's the goal, yes. I've added a note that the maintainers 
> eventually plan on making lexical binding the default.

Oops, I forgot to finish rewording one sentence in my previous patch. 
Here's the fixed version.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 19 Nov 2023 08:40:01 GMT) Full text and rfc822 format available.

Message #41 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: eliz <at> gnu.org, rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in
 Elisp Introduction manual
Date: Sun, 19 Nov 2023 09:38:54 +0100
Jim Porter <jporterbugs <at> gmail.com> writes:

Hi Jim,

> +In some cases, both lexical and dynamic binding behave identically.
> +However, in other cases, they can change the meaning of your program.
> +For example, under lexical binding, if you call a function inside of a
> +@code{let} body, that function's body would be unable to ``see'' (or
> +modify) the value of a local variable from the @code{let} expression:
> +
> +@example
> +;;; -*- lexical-binding: t -*-
> +
> +(setq x 1)
> +
> +(defun getx ()
> +  x)
> +
> +(let ((x 2))
> +  (getx))
> +     @result{} 1
> +@end example
> +
> +@noindent
> +If we use dynamic binding instead, the behavior is different:
> +
> +@example
> +;;; -*- lexical-binding: nil -*-
> +
> +(setq x 1)
> +
> +(defun getx ()
> +  x)
> +
> +(let ((x 2))
> +  (getx))
> +     @result{} 2
> +@end example
> +
> +Now, the result of @samp{(getx)} is @samp{2}!  That's because under
> +dynamic binding, when @code{getx} looks for the value of @code{x}, it
> +sees the value we set in our @code{let} expression.  In other words,
> +the call to @code{getx} happens during the @emph{time} when our
> +@code{let} expression is active.  Under lexical binding, @code{getx}
> +doesn't see the value from our @code{let} expression.  That's because
> +it happens in a different @emph{place} than the @code{let} body.

Would it be worth to emphasize, that a declaration of x changes this?
That is, when a variable is declared, both lexical and dynamic binding
behave identically.

@example
;;; -*- lexical-binding: t -*-

(devfar x 1)

(defun getx ()
  x)

(let ((x 2))
  (getx))
     @result{} 2
@end example

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 19 Nov 2023 20:18:02 GMT) Full text and rfc822 format available.

Message #44 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: eliz <at> gnu.org, rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 19 Nov 2023 12:17:19 -0800
On 11/19/2023 12:38 AM, Michael Albinus wrote:
> Would it be worth to emphasize, that a declaration of x changes this?
> That is, when a variable is declared, both lexical and dynamic binding
> behave identically.

Thanks, that's probably a good idea. We should mention this in the 
section that introduces 'defvar'. I'll work on adding that.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 19 Nov 2023 23:07:01 GMT) Full text and rfc822 format available.

Message #47 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: eliz <at> gnu.org, rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 19 Nov 2023 15:05:55 -0800
[Message part 1 (text/plain, inline)]
On 11/19/2023 12:17 PM, Jim Porter wrote:
> On 11/19/2023 12:38 AM, Michael Albinus wrote:
>> Would it be worth to emphasize, that a declaration of x changes this?
>> That is, when a variable is declared, both lexical and dynamic binding
>> behave identically.
> 
> Thanks, that's probably a good idea. We should mention this in the 
> section that introduces 'defvar'. I'll work on adding that.

Ok, what about this? I just added a mention to the 'defvar' section 
about this, and cross-referenced the two sections.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Mon, 20 Nov 2023 13:29:01 GMT) Full text and rfc822 format available.

Message #50 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: eliz <at> gnu.org, rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in
 Elisp Introduction manual
Date: Mon, 20 Nov 2023 14:28:34 +0100
Jim Porter <jporterbugs <at> gmail.com> writes:

Hi Jim,

> Ok, what about this? I just added a mention to the 'defvar' section
> about this, and cross-referenced the two sections.

Looks OK to me. But perhaps Lisp language experts might have a look on
this also.

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Thu, 23 Nov 2023 02:59:01 GMT) Full text and rfc822 format available.

Message #53 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Wed, 22 Nov 2023 21:57:50 -0500
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

Your work is good.

After this,

  > +;;; -*- lexical-binding: t -*-
  > +
  > +(setq x 1)
  > +
  > +(defun getx ()
  > +  x)
  > +
  > +(let ((x 2))
  > +  (getx))
  > +     @result{} 1
  > +@end example

it could be good to add the following:

+(setq x 3)
+
+(let ((x 2))
+  (getx))
+     @result{} 3
+
+(setq x '(foo))
+
+(let ((x 2))
+  (getx))
+     @result{} (foo)
+@end example

to show that `getx' accesses the current value of the global binding,
not the value that the global binding had when getx was defined.

Adding this to the lexical binding example

+(setq x 3)
+
+(let ((x 2))
+  (getx))
+     @result{} 2
+
+(setq x '(foo))
+
+(let ((x 2))
+  (getx))
+     @result{} 2

could also help, by showing that changes in the global binding's value
are irrelevant for references to x where that binding is shadowed.

Or perhaps this pair of examples should be presented as a separate
point following the other one.
-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Thu, 23 Nov 2023 21:05:02 GMT) Full text and rfc822 format available.

Message #56 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Thu, 23 Nov 2023 13:04:01 -0800
[Message part 1 (text/plain, inline)]
On 11/22/2023 6:57 PM, Richard Stallman wrote:
> it could be good to add the following:
[snip]
> to show that `getx' accesses the current value of the global binding,
> not the value that the global binding had when getx was defined.

How about this? Instead of adding further examples, I made the existing 
ones just a bit more complex (I added another 'setq' after defining the 
function 'getx' to both examples). Then I explained specifically that in 
the lexical binding example, "... 'getx' sees the current global value 
of 'x'."

Hopefully this strikes the right balance between being explicit and 
detailed about what's happening without adding too many twists and turns 
to the section. I wanted to stick with just two blocks of code in this 
section so that a reader who was skimming (or just reading quickly) 
could easily pick them out to compare and contrast with each other. 
Additional code blocks made this harder to do when I tried it.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Fri, 24 Nov 2023 07:07:01 GMT) Full text and rfc822 format available.

Message #59 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Fri, 24 Nov 2023 09:06:11 +0200
> Date: Thu, 23 Nov 2023 13:04:01 -0800
> Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
> From: Jim Porter <jporterbugs <at> gmail.com>
> 
> @@ -3601,25 +3602,22 @@ Prevent confusion
>  @cindex @samp{local variable} defined
>  @cindex @samp{variable, local}, defined
>  The @code{let} special form prevents confusion.  @code{let} creates a
> -name for a @dfn{local variable} that overshadows any use of the same
> -name outside the @code{let} expression.  This is like understanding
> -that whenever your host refers to ``the house'', he means his house, not
> -yours.  (Symbols used in argument lists work the same way.
> +name for a @dfn{local variable} that overrides any use of the same
> +name outside the @code{let} expression (in computer science jargon, we
> +call this ``binding'' the variable).  This is like understanding that
> +in your host's home, whenever he refers to ``the house'', he means his
> +house, not yours.  (Symbols used in argument lists work the same way.
>  @xref{defun, , The @code{defun} Macro}.)

FWIW, I find the use of "overshadows" in the original text to be
better than the "overrides" in the new text.  This is partly because
the meaning of "override" is not clear when talking about the use of a
name, and partly because "override" is really inaccurate here.  If we
are not happy with the original text, then we need to find something
else, IMO, perhaps a more detailed description.

> +@node How let Binds Variables
> +@subsection How @code{let} Binds Variables
> +@cindex Lexical binding
> +@cindex Binding, lexical
> +@cindex Dynamic binding
> +@cindex Binding, dynamic
> +
> +Emacs Lisp supports two different ways of binding variable names to
> +their values.  These ways affect the parts of your program where a
> +particular binding is valid (in computer science jargon, we call these
> +parts a ``scope'').  For historical reasons, Emacs Lisp uses a form of
> +variable binding called ``dynamic binding'' by default.  However, in
> +this manual we discuss the preferred form of binding, called ``lexical
> +binding'', unless otherwise noted (in the future, the Emacs
> +maintainers plan to change the default to lexical binding).  If you
> +have programmed in other languages before, you're likely already
> +familiar with how lexical binding behaves.

Markup note: each of the phrases quoted ``like this'' in this passage
should actually be a @dfn.

> +As we discussed before, under lexical binding, @code{let} defines a
> +@emph{place} in your code where the variables have their own local
> +meaning.  Under dynamic binding, the rules are different: instead, you
> +are defining a @emph{time} in your code when the variables have their
> +own local meaning.

If this wants to explain the difference between compile-time and
run-time binding, then perhaps it should say so, instead of talking
about the confusing "place where" vs "time when" the value changes?
And if compile-time is problematic (Emacs being an interpreter), then
we should find another description, one that doesn't use confusing
concept of "place".

IOW, I don't feel like reading this and the previous description of
'let' I understood the difference between lexical-binding and dynamic
binding.  One problem here is that, in an interpreted environment such
as Emacs Lisp, there's no well-defined notion of "compile-time", and
"time" is deterministically determined by "place".

> +Another way to think about @code{let} when using dynamic binding is
> +that it is like a @code{setq} that is temporary and local.  The values
> +set by @code{let} are automatically undone when the @code{let} is
> +finished.  The setting only affects expressions that are inside the
> +bounds of the @code{let} expression.

The immediate question I had when reading this is how is this
different from the lexical-binding rules.  Isn't the let-binding under
lexical-binding also "temporary and local"? isn't the value also
"undone when 'let' is finished? doesn't the setting only "affect the
expressions that are inside the bounds of 'let'"?

Can the text answer these questions?

> +@example
> +;;; -*- lexical-binding: t -*-
> +
> +(setq x 0)
> +
> +(defun getx ()
> +  x)
> +
> +(setq x 1)
> +
> +(let ((x 2))
> +  (getx))
> +     @result{} 1
> +@end example
> +
> +@noindent
> +Here, the result of @code{(getx)} is @code{1}.  Under lexical binding,
> +@code{getx} doesn't see the value from our @code{let} expression.
> +That's because it happens in a different @emph{place} than the
> +@code{let} body.  Instead, @code{getx} sees the current global value
> +of @code{x}.

It is not really clear here what is meant by "place".  The code shows
3 "places" where x gets a value: the two 'setq's and the 'let'.  It is
left unexplained why 'getx' sees the 2nd place, but not the other two.
So something crucial is missing from this description.

> +Now, the result of @code{(getx)} is @code{2}!  That's because under
> +dynamic binding, when @code{getx} looks for the value of @code{x}, it
> +sees the value we set in our @code{let} expression.  In other words,
> +the call to @code{getx} happens during the @emph{time} when our
> +@code{let} expression is active.

The last sentence should be rephrased.  As written, it states the
obvious: 'getx' is called inside of 'let'.  What it should say instead
is something that would explain why this "during the *time*" part
explains how dynamic binding works, perhaps talking about the last
time a variable gets its value in the run-time sequence of events.
The sentence before that should probably also rephrased accordingly.

> -The @code{defvar} special form is similar to @code{setq} in that it sets
> -the value of a variable.  It is unlike @code{setq} in two ways: first,
> -it only sets the value of the variable if the variable does not already
> -have a value.  If the variable already has a value, @code{defvar} does
> -not override the existing value.  Second, @code{defvar} has a
> -documentation string.
> +The @code{defvar} special form is similar to @code{setq} in that it
> +sets the value of a variable.  It is unlike @code{setq} in three ways:
> +first, it only sets the value of the variable if the variable does not
> +already have a value.  If the variable already has a value,
> +@code{defvar} does not override the existing value.  Second, it marks
> +the variable as ``special'' so that it is always dynamically bound,
> +even when @code{lexical-binding} is @code{t} (@pxref{How let Binds
> +Variables}).  Third, @code{defvar} has a documentation string.

I wonder whether we should make the "second" part be the "first" one
here.

Thanks.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Fri, 24 Nov 2023 09:02:02 GMT) Full text and rfc822 format available.

Message #62 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Fri, 24 Nov 2023 01:01:33 -0800
Thanks for taking a look, Eli. Just a few questions/thoughts on some of 
your comments. (I trimmed the others since I'll probably rework the 
other sections based on how we handle the second part below.)

On 11/23/2023 11:06 PM, Eli Zaretskii wrote:
> FWIW, I find the use of "overshadows" in the original text to be
> better than the "overrides" in the new text.  This is partly because
> the meaning of "override" is not clear when talking about the use of a
> name, and partly because "override" is really inaccurate here.  If we
> are not happy with the original text, then we need to find something
> else, IMO, perhaps a more detailed description.

Maybe we should just leave it as is for now? I don't think it's strictly 
necessary to change that sentence for the rest of the patch to make 
sense. We could always improve it in a follow up.

(Or if someone has the perfect phrase to use here, I'll happily make the 
change. I just don't want the patch to get bogged down by changes that 
are merely *near* the parts I'm working on.)

>> +As we discussed before, under lexical binding, @code{let} defines a
>> +@emph{place} in your code where the variables have their own local
>> +meaning.  Under dynamic binding, the rules are different: instead, you
>> +are defining a @emph{time} in your code when the variables have their
>> +own local meaning.
> 
> If this wants to explain the difference between compile-time and
> run-time binding, then perhaps it should say so, instead of talking
> about the confusing "place where" vs "time when" the value changes?
> And if compile-time is problematic (Emacs being an interpreter), then
> we should find another description, one that doesn't use confusing
> concept of "place".

I'm open to other wordings, but I wanted to describe what's going on 
without getting into the details of the interpreter or how it evaluates 
the code. The "place" is supposed to refer to the actual body of the 
'let' form. That's described in the first part I changed. However, the 
"time" description could probably be expanded.

Maybe we could contrast "within the body of the let expression" vs 
"during execution of the let expression"? That gets across the idea to 
me that the former is about compile-time ("body" refers to the actual 
Lisp form), while the latter is about run-time ("execution").




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Fri, 24 Nov 2023 11:42:01 GMT) Full text and rfc822 format available.

Message #65 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Fri, 24 Nov 2023 13:41:04 +0200
> Date: Fri, 24 Nov 2023 01:01:33 -0800
> Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
> From: Jim Porter <jporterbugs <at> gmail.com>
> 
> >> +As we discussed before, under lexical binding, @code{let} defines a
> >> +@emph{place} in your code where the variables have their own local
> >> +meaning.  Under dynamic binding, the rules are different: instead, you
> >> +are defining a @emph{time} in your code when the variables have their
> >> +own local meaning.
> > 
> > If this wants to explain the difference between compile-time and
> > run-time binding, then perhaps it should say so, instead of talking
> > about the confusing "place where" vs "time when" the value changes?
> > And if compile-time is problematic (Emacs being an interpreter), then
> > we should find another description, one that doesn't use confusing
> > concept of "place".
> 
> I'm open to other wordings, but I wanted to describe what's going on 
> without getting into the details of the interpreter or how it evaluates 
> the code. The "place" is supposed to refer to the actual body of the 
> 'let' form. That's described in the first part I changed. However, the 
> "time" description could probably be expanded.
> 
> Maybe we could contrast "within the body of the let expression" vs 
> "during execution of the let expression"? That gets across the idea to 
> me that the former is about compile-time ("body" refers to the actual 
> Lisp form), while the latter is about run-time ("execution").

"During the execution" is probably a good idea, but "within the body
of the expression" Does not seem to contrast with that, since it also
holds for dynamic binding.

I think the explanation should focus on the code of getx, not on the
code in the 'let'-form's body.  The reason for what happens under
lexical binding is in getx.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Fri, 24 Nov 2023 21:48:02 GMT) Full text and rfc822 format available.

Message #68 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Fri, 24 Nov 2023 13:46:55 -0800
[Message part 1 (text/plain, inline)]
On 11/24/2023 3:41 AM, Eli Zaretskii wrote:
> "During the execution" is probably a good idea, but "within the body
> of the expression" Does not seem to contrast with that, since it also
> holds for dynamic binding.

For "within the body of the expression", I wanted a phrase I could use 
near the beginning of this discussion, before we get into the 
differences of lexical vs dynamic binding. That way, I can refer back to 
it in the lexical/dynamic binding section and contrast it with the 
dynamic binding definition.

I've added some more explanation to it though, so hopefully that helps 
clarify things. I also reworked the description of dynamic binding to 
talk about how each variable has a stack of bindings. Hopefully this is 
clear enough; I think it's more straightforward than the previous one, 
since it uses a stack of papers on one's desk as a visual analogy to 
help drive the point home.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sat, 25 Nov 2023 07:53:02 GMT) Full text and rfc822 format available.

Message #71 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sat, 25 Nov 2023 09:51:48 +0200
> Date: Fri, 24 Nov 2023 13:46:55 -0800
> Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
> From: Jim Porter <jporterbugs <at> gmail.com>
> 
> +Another way to think about @code{let} is that it defines a special
> +region in your code: within the body of the @code{let} expression, the
> +variables you've named have their own local meaning.  Outside of the
> +@code{let} body, they have other meanings (or they may not be defined
> +at all).  In practice, this means that inside the @code{let} body,
> +calling @code{setq} for a variable named by the @code{let} expression
> +will set the value of the @emph{local} variable of that name.
> +However, outside of the @code{let} body, calling @code{setq} for a
> +variable named by the @code{let} expression will @emph{not} affect
> +that local variable.

I think something is missing from this description: "inside the 'let'
body" is ambiguous when the body calls functions.  The text should
explain that the body of functions called from 'let' is NOT considered
to be "inside the 'let' body".  This crucial point is hinted or
explained later, but it must be explained right here at the start.

> +As we discussed before, when you create local variables with
> +@code{let} under lexical binding, those variables are valid only
> +within the body of the @code{let} expression.  In other parts of your
> +code, they have other meanings, so if you call a function in the
> +@code{let} body, that function would be unable to ``see'' the local
> +variables you've created.

First, AFAIU the last sentence is correct only if the function's
definition is outside of the 'let'.  And second, this crucial
dependence on where the function is defined is very important for
understanding _why_ the function won't see the value bound by 'let'.
So it must be in the text, IMO.

> +Under dynamic binding, the rules are different: instead, when you use
> +@code{let}, the local variables you've created are valid during
> +execution of the let expression.  This means that, if your @code{let}
> +expression calls a function, that function can see (and modify) these
> +local variables.

This should say "...regardless of where the function is defined."  I
would even add that the above is true even for functions defined on
other Lisp files.

> +Another way to think about @code{let} when using dynamic binding is
> +that every variable name has a ``stack'' of bindings, and whenever you
> +use that variable's name, it refers to the binding on the top of the
> +stack.  (You can imagine this like a stack of papers on your desk with
> +the values written on them.)  When you bind a variable with
> +@code{let}, it puts the new binding you've specified on the top of the
> +stack, and then executes the @code{let} body.  Once the @code{let}
> +body finishes, it takes that binding off of the stack, revealing the
> +one it had (if any) before the @code{let} expression.

This should IMO tell that this "binding stack" is _global_, i.e. it is
seen by every function regardless of where and how it was defined.

> +Here, the result of @code{(getx)} is @code{1}.  Under lexical binding,
> +@code{getx} doesn't see the value from our @code{let} expression.
> +That's because the body of @code{getx} is outside of the body of our
> +@code{let} expression.

The last sentence is critical for understanding of the issue, and
should be at the very beginning of the 'let' description (and repeated
here, of course).

>                          Instead, @code{getx} looks for @code{x}
> +elsewhere, and finds it at the global scope of our code.

This "looks for and finds" is problematic, IMO, because it is not
clear why would it "find" the value of x set by 'setq', but not the
value of x set by 'let'.  IOW, the mechanism of "looking and finding"
remains mysterious and no intuitive description is provided to help
understanding it.  Can we provide such a description?  If you cannot
think about one, how about explaining the internal workings of this
"looking and finding" as it is implemented, and we could then take it
from there and express the idea in less technical ways.

> +Now, the result of @code{(getx)} is @code{2}!  That's because under
> +dynamic binding, when executing @code{getx}, the current binding for
> +@code{x} is the one from our @code{let} binding.  This time,
> +@code{getx} doesn't see the global value for @code{x}, since its
> +binding is below the one from our @code{let} expression in the stack
> +of bindings.

This should mention the stack and its top earlier, where it talks
about "the current binding".

Thanks.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Thu, 30 Nov 2023 21:05:02 GMT) Full text and rfc822 format available.

Message #74 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Thu, 30 Nov 2023 13:03:52 -0800
[Message part 1 (text/plain, inline)]
On 11/24/2023 11:51 PM, Eli Zaretskii wrote:
> I think something is missing from this description: "inside the 'let'
> body" is ambiguous when the body calls functions.  The text should
> explain that the body of functions called from 'let' is NOT considered
> to be "inside the 'let' body".  This crucial point is hinted or
> explained later, but it must be explained right here at the start.

I added a short parenthetical here to explain this point: "(such as when 
calling a function that was defined elsewhere)". I intentionally kept 
this brief though, since this introductory section is primarily about 
introducing the basics of 'let' and why you'd use it. Once we've shown 
readers *how* to use 'let', then we return to a more detailed discussion 
of how the binding works in the last section.

>> +As we discussed before, when you create local variables with
>> +@code{let} under lexical binding, those variables are valid only
>> +within the body of the @code{let} expression.  In other parts of your
>> +code, they have other meanings, so if you call a function in the
>> +@code{let} body, that function would be unable to ``see'' the local
>> +variables you've created.
> 
> First, AFAIU the last sentence is correct only if the function's
> definition is outside of the 'let'.  And second, this crucial
> dependence on where the function is defined is very important for
> understanding _why_ the function won't see the value bound by 'let'.
> So it must be in the text, IMO.

I've expanded upon this and added a description of what happens when you 
call a function defined within a 'let' body.

>> +Under dynamic binding, the rules are different: instead, when you use
>> +@code{let}, the local variables you've created are valid during
>> +execution of the let expression.  This means that, if your @code{let}
>> +expression calls a function, that function can see (and modify) these
>> +local variables.
> 
> This should say "...regardless of where the function is defined."  I
> would even add that the above is true even for functions defined on
> other Lisp files.

Done.

> This should IMO tell that this "binding stack" is _global_, i.e. it is
> seen by every function regardless of where and how it was defined.

Done.

>> +Here, the result of @code{(getx)} is @code{1}.  Under lexical binding,
>> +@code{getx} doesn't see the value from our @code{let} expression.
>> +That's because the body of @code{getx} is outside of the body of our
>> +@code{let} expression.
> 
> The last sentence is critical for understanding of the issue, and
> should be at the very beginning of the 'let' description (and repeated
> here, of course).

Done.

>>                           Instead, @code{getx} looks for @code{x}
>> +elsewhere, and finds it at the global scope of our code.
> 
> This "looks for and finds" is problematic, IMO, because it is not
> clear why would it "find" the value of x set by 'setq', but not the
> value of x set by 'let'.  IOW, the mechanism of "looking and finding"
> remains mysterious and no intuitive description is provided to help
> understanding it.  Can we provide such a description?  If you cannot
> think about one, how about explaining the internal workings of this
> "looking and finding" as it is implemented, and we could then take it
> from there and express the idea in less technical ways.

I've reworded this to hopefully be more explicit that, since 'getx' is 
defined outside of any 'let' body, it will look for 'x' at global scope. 
Combined with the previous, more-general discussion of how 'let' and 
'defun' interact, I think (hope) this should cover things.

>> +Now, the result of @code{(getx)} is @code{2}!  That's because under
>> +dynamic binding, when executing @code{getx}, the current binding for
>> +@code{x} is the one from our @code{let} binding.  This time,
>> +@code{getx} doesn't see the global value for @code{x}, since its
>> +binding is below the one from our @code{let} expression in the stack
>> +of bindings.
> 
> This should mention the stack and its top earlier, where it talks
> about "the current binding".

Done.
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Fri, 01 Dec 2023 08:31:01 GMT) Full text and rfc822 format available.

Message #77 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>, Richard Stallman <rms <at> gnu.org>
Cc: 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Fri, 01 Dec 2023 10:29:47 +0200
> Date: Thu, 30 Nov 2023 13:03:52 -0800
> Cc: rms <at> gnu.org, 66756 <at> debbugs.gnu.org
> From: Jim Porter <jporterbugs <at> gmail.com>
> 
> Done.

Thanks, I'm happy with this text now.

Richard, would you please read the latest patch posted by Jim and
comment on it?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Mon, 04 Dec 2023 03:09:02 GMT) Full text and rfc822 format available.

Message #80 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 03 Dec 2023 22:08:37 -0500
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > +means his house, not yours.  (Symbols used in argument lists work the
  > +same way.

Maybe that sentence should be more explicit about which symbols it
refers to and which aspect of "working".  Perhaps like this:

   (The symbols used to name function arguments are bound as local variables
   in exactly the same way.)

This statement

      However, outside
    +of the @code{let} body (such as when calling a function that was
    +defined elsewhere), calling @code{setq} for a variable named by the
    +@code{let} expression will @emph{not} affect that local variable.

is true only in lexical binding.  With dynamic binding, such a setq
_will_ set the let's local variable (in the simplest cases).

    +Emacs Lisp supports two different ways of binding variable names to
    +their values.  These ways affect the parts of your program where a
    +particular binding is validscop.

Typo there.

    +As we discussed before, when you create local variables with
    +@code{let} under lexical binding, those variables are valid only
    +within the body of the @code{let} expression.

Where is this previous discussion?  I don't see it.  The distinction
of dynamic vs lexical was first introduced two paragraphs above,
and its effects on binding have not been discussed yet.

Is this a reference to the following?

      However, outside
    +of the @code{let} body (such as when calling a function that was
    +defined elsewhere), calling @code{setq} for a variable named by the
    +@code{let} expression will @emph{not} affect that local variable.

That may be meant as a discussion of local binding with lexical scoping,
but it isn't one, since it doesn't say "lexical scoping."

      (On the other hand, if
    +you call a function defined within a @code{let} body,

I recommend "that was defined within"; it is more clear.

    +Under dynamic binding, the rules are different: instead, when you use
    +@code{let}, the local variables you've created are valid during
    +execution of the let expression.

@code needed here.

      When you bind a variable
    +with @code{let}, it puts the new binding you've specified on the top
    +of the stack,

For clarity, I suggest "bind a variable dynamically" or something to reiterate
that this sentence is only about dynamic binding.  Without that, the reader
could take it to be independent of which mode is currently selected.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Mon, 04 Dec 2023 03:09:02 GMT) Full text and rfc822 format available.

Message #83 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Jim Porter <jporterbugs <at> gmail.com>
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 03 Dec 2023 22:08:39 -0500
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

The new node How let Binds Variables is 110 lines long.  Such a long
node is cumbersome, especially for cross-references to it.

Can you find a way to subdivide it into smaller nodes?

It could have some text at the beginning, then a few subnodes.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Mon, 04 Dec 2023 03:10:02 GMT) Full text and rfc822 format available.

Message #86 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: jporterbugs <at> gmail.com, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 03 Dec 2023 22:08:43 -0500
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > Richard, would you please read the latest patch posted by Jim and
  > comment on it?

Thanks for suggesting I do that.  I've sent my comments now.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Mon, 04 Dec 2023 04:36:02 GMT) Full text and rfc822 format available.

Message #89 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 3 Dec 2023 20:34:49 -0800
[Message part 1 (text/plain, inline)]
On 12/3/2023 7:08 PM, Richard Stallman wrote:
> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
> 
>    > +means his house, not yours.  (Symbols used in argument lists work the
>    > +same way.
> 
> Maybe that sentence should be more explicit about which symbols it
> refers to and which aspect of "working".  Perhaps like this:
> 
>     (The symbols used to name function arguments are bound as local variables
>     in exactly the same way.)

Makes sense to me. Done.

> This statement
> 
>        However, outside
>      +of the @code{let} body (such as when calling a function that was
>      +defined elsewhere), calling @code{setq} for a variable named by the
>      +@code{let} expression will @emph{not} affect that local variable.
> 
> is true only in lexical binding.  With dynamic binding, such a setq
> _will_ set the let's local variable (in the simplest cases).

Correct. Based on Eli's suggestions, I've worded this initial section to 
assume that lexical binding is in effect. I put a footnote here to 
mention this, but otherwise I'm trying my hardest to avoid front-loading 
the 'let' documentation with an explanation of lexical binding.

>      +Emacs Lisp supports two different ways of binding variable names to
>      +their values.  These ways affect the parts of your program where a
>      +particular binding is validscop.
> 
> Typo there.

Thanks. I think that was a mistake from when I was searching for "scope" 
to ensure I didn't inadvertently use the term in this section. (I wanted 
to avoid mentioning another CS term here, and I think "binding" is 
enough for what we want to say.)

>      +As we discussed before, when you create local variables with
>      +@code{let} under lexical binding, those variables are valid only
>      +within the body of the @code{let} expression.
> 
> Where is this previous discussion?  I don't see it.  The distinction
> of dynamic vs lexical was first introduced two paragraphs above,
> and its effects on binding have not been discussed yet.
> 
> Is this a reference to the following?
> 
>        However, outside
>      +of the @code{let} body (such as when calling a function that was
>      +defined elsewhere), calling @code{setq} for a variable named by the
>      +@code{let} expression will @emph{not} affect that local variable.
> 
> That may be meant as a discussion of local binding with lexical scoping,
> but it isn't one, since it doesn't say "lexical scoping."

Correct. I added a cross-reference back to that section. With that and 
the footnote in the "let Prevents Confusion" section, hopefully this is 
clearer now.

>        (On the other hand, if
>      +you call a function defined within a @code{let} body,
> 
> I recommend "that was defined within"; it is more clear.

Done.

>      +Under dynamic binding, the rules are different: instead, when you use
>      +@code{let}, the local variables you've created are valid during
>      +execution of the let expression.
> 
> @code needed here.

Fixed.

>        When you bind a variable
>      +with @code{let}, it puts the new binding you've specified on the top
>      +of the stack,
> 
> For clarity, I suggest "bind a variable dynamically" or something to reiterate
> that this sentence is only about dynamic binding.  Without that, the reader
> could take it to be independent of which mode is currently selected.

Done.

On 12/3/2023 7:08 PM, Richard Stallman wrote:
> The new node How let Binds Variables is 110 lines long.  Such a long
> node is cumbersome, especially for cross-references to it.
> 
> Can you find a way to subdivide it into smaller nodes?
> 
> It could have some text at the beginning, then a few subnodes.

I've split this into a main section and two subnodes: one describing how 
lexical and dynamic binding work, and one showing an example of how they 
behave differently in practice. Maybe the titles could be improved, but 
they're the best I could come up with at the time...
[0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 10 Dec 2023 19:37:01 GMT) Full text and rfc822 format available.

Message #92 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 10 Dec 2023 11:36:06 -0800
On 12/3/2023 8:34 PM, Jim Porter wrote:
> I've split this into a main section and two subnodes: one describing how 
> lexical and dynamic binding work, and one showing an example of how they 
> behave differently in practice. Maybe the titles could be improved, but 
> they're the best I could come up with at the time...

Does anyone have any further comments on this patch? If not, I'll merge 
it into the master branch in the next few days. (Of course, we can 
always improve it more after merging if someone has a suggestion.)




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sat, 16 Dec 2023 23:11:02 GMT) Full text and rfc822 format available.

Message #95 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Kangas <stefankangas <at> gmail.com>
To: Jim Porter <jporterbugs <at> gmail.com>, rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sat, 16 Dec 2023 15:10:08 -0800
Jim Porter <jporterbugs <at> gmail.com> writes:

> On 12/3/2023 8:34 PM, Jim Porter wrote:
>> I've split this into a main section and two subnodes: one describing how
>> lexical and dynamic binding work, and one showing an example of how they
>> behave differently in practice. Maybe the titles could be improved, but
>> they're the best I could come up with at the time...
>
> Does anyone have any further comments on this patch? If not, I'll merge
> it into the master branch in the next few days. (Of course, we can
> always improve it more after merging if someone has a suggestion.)

I suggest merging it to emacs-29.  If we indeed think it's better, let's
get the improved documentation into users' hands.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#66756; Package emacs. (Sun, 17 Dec 2023 20:48:01 GMT) Full text and rfc822 format available.

Message #98 received at 66756 <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Stefan Kangas <stefankangas <at> gmail.com>, rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756 <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Sun, 17 Dec 2023 12:47:41 -0800
On 12/16/2023 3:10 PM, Stefan Kangas wrote:
> Jim Porter <jporterbugs <at> gmail.com> writes:
> 
>> Does anyone have any further comments on this patch? If not, I'll merge
>> it into the master branch in the next few days. (Of course, we can
>> always improve it more after merging if someone has a suggestion.)
> 
> I suggest merging it to emacs-29.  If we indeed think it's better, let's
> get the improved documentation into users' hands.

Sounds good to me. I'll give people another day or two to raise any last 
concerns, and if there aren't any, I'll merge to the 29 branch.




Reply sent to Jim Porter <jporterbugs <at> gmail.com>:
You have taken responsibility. (Tue, 09 Jan 2024 18:42:03 GMT) Full text and rfc822 format available.

Notification sent to Jim Porter <jporterbugs <at> gmail.com>:
bug acknowledged by developer. (Tue, 09 Jan 2024 18:42:03 GMT) Full text and rfc822 format available.

Message #103 received at 66756-done <at> debbugs.gnu.org (full text, mbox):

From: Jim Porter <jporterbugs <at> gmail.com>
To: Stefan Kangas <stefankangas <at> gmail.com>, rms <at> gnu.org
Cc: eliz <at> gnu.org, 66756-done <at> debbugs.gnu.org
Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp
 Introduction manual
Date: Tue, 9 Jan 2024 10:40:47 -0800
Version: 29.2

On 12/17/2023 12:47 PM, Jim Porter wrote:
> On 12/16/2023 3:10 PM, Stefan Kangas wrote:
>> Jim Porter <jporterbugs <at> gmail.com> writes:
>>
>> I suggest merging it to emacs-29.  If we indeed think it's better, let's
>> get the improved documentation into users' hands.
> 
> Sounds good to me. I'll give people another day or two to raise any last 
> concerns, and if there aren't any, I'll merge to the 29 branch.

I've now merged the latest revision of my patch to the release branch as 
d58d0fa52ff. Closing this bug.

Of course, if anyone sees any further issues, just let me know and I'll 
try to address them.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Wed, 07 Feb 2024 12:24:13 GMT) Full text and rfc822 format available.

This bug report was last modified 1 year and 93 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.