bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp Introdu


From: Jim Porter
Subject: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp Introduction manual
Date: Thu, 30 Nov 2023 13:03:52 -0800

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.

Attachment: 0001-Introduce-let-using-lexical-binding-in-the-Lisp-Intr.patch
Description: Text document


reply via email to

[Prev in Thread] Current Thread [Next in Thread]