Subject: Re: bug#59333: [PATCH] Define macro dlet*

From: daanturo <[email-masked]>
Date: Sat, 19 Nov 2022 12:29:24 +0700

On @ 2022-11-17 13:36, Mattias Engdegård wrote:
> The proposed patch also appears incorrect

It was a mistake when I copying and pasting. This patch corrected that and
removed the erroneous breakage mention.

If there would ever be a vote to reduce the number of `let` variants to lighten
the maintenance burden, I bet that the `let*` ones will remain instead of the
versions without the ability to refer to prior bindings. As `let*` can cover
`let` but the reverse is impossible.

```emacs-lisp
(let* ((_a a)
       (a (+ 1 _a))
       (b (+ 2 _a))))
```

Therefore, in my opinion, new `XXXlet` macros variants should be defined like
`XXXlet*` instead, maybe with only `XXXlet*` without `XXXlet`, since we will
eventually need an asterisk version in the future anyway. (Also dash-like easy
destructuring is sweet if possible.)

Why do need to define (publicly) then maintain for eternity `letf`, `flet`,
`dlet`, `lexical-let`, `pcase-let`, `if-let`, `when-let`, etc. when only their
`*` versions should be exposed and encompass every use case just fine?

I think `and-let*` is the most sensible case here as it doesn't have a more
limited `and-let` version.

On 19/11/2022 11:47, Jean Louis wrote:
> * daanturo <[email-masked]> [2022-11-17 10:16]:
>> --=-=-=
>> Content-Type: text/plain
>>
>> Tags: patch
>>
>>
>> The dlet breakage comes as much surprise to me. There's not even a
>> single entry in NEWS that mentions it.
>>
>>
>> The last line of `dlet' is now:  (let ,binders ,@body))) while I need
>> it to be as below:      (let* ,binders ,@body))
>>
>>
-- 
Daanturo.
From 57fa015d03232e5517cb6d2082d24ef18ca88e24 Mon Sep 17 00:00:00 2001
From: Daanturo <[email-masked]>
Date: Sat, 19 Nov 2022 12:02:35 +0700
Subject: [PATCH] Define macro dlet*

* lisp/subr.el: implementation.
* doc/lispref/variables.texi: documentation.
* etc/NEWS: announce it.
---
 doc/lispref/variables.texi | 6 ++++++
 etc/NEWS                   | 5 +++++
 lisp/subr.el               | 8 ++++++++
 3 files changed, 19 insertions(+)

diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index 7206f2acd2..11a0f220ca 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -303,6 +303,12 @@ Local Variables
 the forms, and then make the variables non-special again.
 @end defspec
 
+@defspec dlet* (bindings@dots{}) forms@dots{}
+This form is like @code{dlet}, but each valueform can refer to the
+symbols already bound previously, like what @code{let*} is to
+@code{let}.
+@end defspec
+
 @defspec named-let name bindings &rest body
 This special form is a looping construct inspired from the
 Scheme language.  It is similar to @code{let}: It binds the variables in
diff --git a/etc/NEWS b/etc/NEWS
index 0b8f4539f9..11f9ccb26a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3269,6 +3269,11 @@ The following generalized variables have been made obsolete:
 
 * Lisp Changes in Emacs 29.1
 
+
++++
+** New macro 'dlet*'.
+Like what 'let*' is to 'let'.
+
 +++
 ** Interpreted closures are "safe for space".
 As was already the case for byte-compiled closures, instead of capturing
diff --git a/lisp/subr.el b/lisp/subr.el
index 6b83196d05..ecca52f99e 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2155,6 +2155,14 @@ dlet
                binders)
      (let ,binders ,@body)))
 
+(defmacro dlet* (binders &rest body)
+  "Like `let*' but using dynamic scoping."
+  (declare (indent 1) (debug let))
+  `(let (_)
+     ,@(mapcar (lambda (binder)
+                 `(defvar ,(if (consp binder) (car binder) binder)))
+               binders)
+     (let* ,binders ,@body)))
 
 (defmacro with-wrapper-hook (hook args &rest body)
   "Run BODY, using wrapper functions from HOOK with additional ARGS.
-- 
2.38.1