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

From: Eli Zaretskii <[email-masked]>
Date: Fri, 24 Nov 2023 09:06:11 +0200

> Date: Thu, 23 Nov 2023 13:04:01 -0800
> Cc: [email-masked], [email-masked]
> From: Jim Porter <[email-masked]>
> 
> @@ -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.