Subject: Re: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp Introduction manual

From: Jim Porter <[email-masked]>
Date: Thu, 26 Oct 2023 11:30:46 -0700

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

From 12847e0d59b2de3791efa090addc0169e713e6d1 Mon Sep 17 00:00:00 2001
From: Jim Porter <[email-masked]>
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