From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier via "Emacs development discussions." Newsgroups: gmane.emacs.devel Subject: Re: Code for cond* Date: Tue, 23 Jan 2024 13:10:01 -0500 Message-ID: References: Reply-To: Stefan Monnier Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="38010"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) To: emacs-devel@gnu.org Cancel-Lock: sha1:7KM6SIMhyB1iW8HDdQ7IK4kPdvo= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Tue Jan 23 19:10:49 2024 Return-path: Envelope-to: ged-emacs-devel@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 1rSLEW-0009jC-OA for ged-emacs-devel@m.gmane-mx.org; Tue, 23 Jan 2024 19:10:48 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rSLE3-0003Mc-2W; Tue, 23 Jan 2024 13:10:19 -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 1rSLE1-0003Lt-FT for emacs-devel@gnu.org; Tue, 23 Jan 2024 13:10:17 -0500 Original-Received: from ciao.gmane.io ([116.202.254.214]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rSLDy-0004OQ-UP for emacs-devel@gnu.org; Tue, 23 Jan 2024 13:10:17 -0500 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1rSLDu-0008q1-Kl for emacs-devel@gnu.org; Tue, 23 Jan 2024 19:10:10 +0100 X-Injected-Via-Gmane: http://gmane.org/ Received-SPF: pass client-ip=116.202.254.214; envelope-from=ged-emacs-devel@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.249, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:315266 Archived-At: > Here is the first draft of cond*. I have tested some cases > but I ask others to help in testing it more thoroughly. AFAICT the main reason to oppose the use of `pcase` is that it increases the size of the language, making it harder for non-experts to read/understand/modify ELisp code. `cond*` suffers from the same criticism. And having both even more so (and whether you like it or not, `pcase` is probably not going to disappear any time soon, among other things because it offers a style familiar from other languages and that style is gaining popularity). So, I'm not super enthusiastic about adding such a new form, but being responsible for the introduction of several such new constructs in ELisp over the years, I do feel a bit like the pot calling the kettle black. So, rather than oppose it, I'll just point out some things which I think could be improved (or which offend my taste, as the case may be). > (cond* > ;; Same as a clause in `cond', > (CONDITION > DO-THIS-IF-TRUE-THEN-EXIT...) So far so good. > ;; Execute FORM, and ignore its value > ;; (except if this is the last clause). > (FORM) YAGNI. > ;; Variables to bind, as in let*, around the rest > ;; of the cond*. > ((bind* (x foobar) y z (foo 5) a)) > ;; Bindings continue in effect for the whole cond* construct. This is one of the functionality missing from `cond`, so I'm rather favorable, but: - why `bind*` when the rest of ELisp uses `let*` in the names of all related constructs? - Why the double parens? - Why `*`? If you need such sequential bindings, you can get it with (cond [...] ((bind* (x E1))) ((bind* (y (foo x)))) So here a plain old "parallel let" would be more useful (or restrict that binding to a single var, so the question doesn't even pop up). > ;; Bind variables for the clause, as in let*. > ((bind* (foo 5) (condition (hack-it foo))) > ;; condition is that the last variable bound be non-nil. > BODY...) This is the other of the functionality missing from `cond`, so I'm rather favorable, but: - why `bind*` when the rest of ELisp uses "let*" in the names of all related constructs? - I'm not happy about using the same construct for "bindings for this clause" and "bindings for subsequent clauses". Maybe it should be inspired by `when-let*`? > ;; Extracts substructure and binds variables for the clause. > ((match* `(expt ,foo ,bar) x) > DO-THIS-IF-IT-MATCHED-THEN-EXIT...) > ;; Bindings no longer in effect. This `(expt ,foo ,bar) is a valid Pcase pattern, so it would be odd if other Pcase patterns can't be used here. For that same reason, it's odd for its name not to include "pcase". > ((match* `(expt ,foo ,bar) x)) > ;; Bindings continue in effect. Same comment as before: I like having both "bindings for the clause" and "bindings for the rest", but having the two be syntactically identical will lead to confusion. Finally, I see a fairly extensive but hardcoded pattern language, which seems like a regression compared to Pcase where the pattern language is built from a few primitives only (with the rest defined on top via `pcase-defmacro`). The worst part, tho, is that the two pattern languages are very similar, and I can't see any good reason for the differences. It feels like an NIH reaction. Stefan