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: Fri, 24 Nov 2023 09:06:11 +0200 Message-ID: <83jzq7fx5o.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> Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="18997"; 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 Fri Nov 24 08:07:24 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 1r6QHa-0004iS-7Y for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 24 Nov 2023 08:07:22 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r6QHD-0003Cl-03; Fri, 24 Nov 2023 02:06: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 1r6QHC-0003Cc-6X for bug-gnu-emacs@gnu.org; Fri, 24 Nov 2023 02:06: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 1r6QHB-00051O-Uu for bug-gnu-emacs@gnu.org; Fri, 24 Nov 2023 02:06:57 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1r6QHF-0008FK-TN for bug-gnu-emacs@gnu.org; Fri, 24 Nov 2023 02:07:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 24 Nov 2023 07:07:01 +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.170080959831667 (code B ref 66756); Fri, 24 Nov 2023 07:07:01 +0000 Original-Received: (at 66756) by debbugs.gnu.org; 24 Nov 2023 07:06:38 +0000 Original-Received: from localhost ([127.0.0.1]:35529 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r6QGs-0008Ef-1Y for submit@debbugs.gnu.org; Fri, 24 Nov 2023 02:06:38 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:43968) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1r6QGp-0008ET-V3 for 66756@debbugs.gnu.org; Fri, 24 Nov 2023 02:06:36 -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 1r6QGg-0004yx-6T; Fri, 24 Nov 2023 02:06:26 -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=aIX3f18NZPFBqY/hWf5E3+eGhXaPo4UqIkFe3LGZNGc=; b=GCT23NZWYehO E2sKsqAdXtcMtBXomjqTDJ2cpr8+LPWmgqy2GqZmYp2ftqYsS3XZ0tvhmpR6T0mTlYKWzbVcKB/w+ cYMcrGAdvtxU7Z4cUGauoY1HboIlxzrcrhsMt//bYt3ur2CcP/PQ9tTDoCw3Mq+GTc2THRlg/eqe8 eCgkdlTSpVCLADFmtJdLLcYGDxkvbm4wko/A4bcCIhFR4WXedY+95JO7jsGE88KjuERSdSM0IPUdD VENBwU1xRSKWj5q4R1JH0A+rlebkukj6QL+WIcVBcan4CNA1i0yQNkLYVDaHBIYzcJEgH8Mqsr5dH zEIbocNOrq0QW7WDqXgJdg==; In-Reply-To: <9239b6bd-b476-b6c1-aef9-245e439aee42@gmail.com> (message from Jim Porter on Thu, 23 Nov 2023 13:04:01 -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:274840 Archived-At: > Date: Thu, 23 Nov 2023 13:04:01 -0800 > Cc: eliz@gnu.org, 66756@debbugs.gnu.org > From: Jim Porter > > @@ -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.