From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Eli Zaretskii Newsgroups: gmane.emacs.bugs Subject: bug#66756: 30.0.50; [PATCH] Improve discussion of 'let' in Elisp Introduction manual Date: Sat, 25 Nov 2023 09:51:48 +0200 Message-ID: <83jzq6e0dn.fsf@gnu.org> References: <3ade119d-0f0d-e60e-1bdc-9c7e02c1559c@gmail.com> <381836df-c16f-b3e7-d0c4-473290e165de@gmail.com> <9239b6bd-b476-b6c1-aef9-245e439aee42@gmail.com> <83jzq7fx5o.fsf@gnu.org> <64d90b0b-e003-7bc3-5312-6c7ab4c4591f@gmail.com> <838r6nfkfj.fsf@gnu.org> Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="30632"; mail-complaints-to="usenet@ciao.gmane.io" Cc: rms@gnu.org, 66756@debbugs.gnu.org To: Jim Porter Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Nov 25 08:53:23 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1r6nTf-0007m2-DU for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 25 Nov 2023 08:53:23 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r6nTH-0007UQ-9u; Sat, 25 Nov 2023 02:52:59 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r6nTG-0007T9-0A for bug-gnu-emacs@gnu.org; Sat, 25 Nov 2023 02:52:58 -0500 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1r6nTF-00067K-Ns for bug-gnu-emacs@gnu.org; Sat, 25 Nov 2023 02:52:57 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1r6nTK-0006wR-8d for bug-gnu-emacs@gnu.org; Sat, 25 Nov 2023 02:53:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 25 Nov 2023 07:53:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 66756 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 66756-submit@debbugs.gnu.org id=B66756.170089873826618 (code B ref 66756); Sat, 25 Nov 2023 07:53:02 +0000 Original-Received: (at 66756) by debbugs.gnu.org; 25 Nov 2023 07:52:18 +0000 Original-Received: from localhost ([127.0.0.1]:37693 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r6nSb-0006vG-Es for submit@debbugs.gnu.org; Sat, 25 Nov 2023 02:52:17 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:50894) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r6nSX-0006v1-6O for 66756@debbugs.gnu.org; Sat, 25 Nov 2023 02:52:15 -0500 Original-Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r6nSL-0005ye-IR; Sat, 25 Nov 2023 02:52:02 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=fn8uZPNGYjVKr5Z9Gykm3TWQi55C/CW9G0e/AzHlg68=; b=kI5JO8kuJPmK xWlZdNhv90Dfy4nt0ZXh3XJoc6nJbtO+uVJ6hm74OaHh76Tvp8hyXPS5jSZ3I5Rg76OqvsHIPxEvX zkA/TO+OAzM8sqvme0sMK+Rj+lzwnusZZK2Rga2PydBJa7moHTx0z21NLsKVoii1RJllQfOXwF51q PGFW0BR3uCFStO/ibGxp/k6uRMYefcNoZ0/PBbHpuNFpCJaxxRTEt3c6gRoj9/BJzRIoAxC3HBJR9 OYtWJNH/jVMiaEZEMoPfa7J/ImpKuFeW40eSWtfvQusIpz7PDgYrIyWc96P0yvfuVlmDTzC8TbZrl qP/yxGErvT6tO1crEVmZ4A==; In-Reply-To: (message from Jim Porter on Fri, 24 Nov 2023 13:46:55 -0800) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:274917 Archived-At: > Date: Fri, 24 Nov 2023 13:46:55 -0800 > Cc: rms@gnu.org, 66756@debbugs.gnu.org > From: Jim Porter > > +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.