unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
@ 2024-01-16 15:07 Ihor Radchenko
  2024-01-16 16:52 ` Jim Porter
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-16 15:07 UTC (permalink / raw)
  To: 68509

Hi,

Consider the following

(pcase-dolist (`(,(and (pred stringp) a) .
		 ,(and (pred stringp) b))
	       '(("TODO") ("DONE" . "a")))
  (warn "%S :: %S" a b))

Executing the above yields

⛔ Warning (emacs): "TODO" :: nil
⛔ Warning (emacs): "DONE" :: "a"

even though ("TODO") does not match the pattern.

In contrast

(dolist (el '(("TODO") ("DONE" . "a")))
  (pcase el
    (`(,(and (pred stringp) a) .
       ,(and (pred stringp) b))
     (warn "%S :: %S" a b))))

correctly displays

⛔ Warning (emacs): "DONE" :: "a"


In GNU Emacs 30.0.50 (build 8, x86_64-pc-linux-gnu, GTK+ Version
 3.24.39, cairo version 1.18.0) of 2024-01-16 built on localhost
Repository revision: 5f73258753ee91c8648e0be55332f7dbaea9fa8b
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101010
System Description: Gentoo Linux


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-01-16 15:07 bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly Ihor Radchenko
@ 2024-01-16 16:52 ` Jim Porter
  2024-01-16 18:43   ` Ihor Radchenko
  2024-02-19 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 21+ messages in thread
From: Jim Porter @ 2024-01-16 16:52 UTC (permalink / raw)
  To: Ihor Radchenko, 68509

On 1/16/2024 7:07 AM, Ihor Radchenko wrote:
> Consider the following
> 
> (pcase-dolist (`(,(and (pred stringp) a) .
> 		 ,(and (pred stringp) b))
> 	       '(("TODO") ("DONE" . "a")))
>    (warn "%S :: %S" a b))
> 
> Executing the above yields
> 
> ⛔ Warning (emacs): "TODO" :: nil
> ⛔ Warning (emacs): "DONE" :: "a"
> 
> even though ("TODO") does not match the pattern.

This isn't an issue with 'pcase-dolist', but rather a known/intentional 
limitation of 'pcase-let':

(pcase-let ((`(,(and (pred stringp) a) .
                ,(and (pred stringp) b))
              '("TODO")))
   (warn "%S :: %S" a b))
   -> Warning (emacs): "TODO" :: nil

The 'pcase-let' docstring says this:

> Each EXP should match (i.e. be of compatible structure) to its
> respective PATTERN; a mismatch may signal an error or may go
> undetected, binding variables to arbitrary values, such as nil.

I do think we should fix it somehow though. This behavior is extremely 
confusing, and as much as I'm a fan of 'pcase', I'm emphatically *not* a 
fan of how this part works.





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-01-16 16:52 ` Jim Porter
@ 2024-01-16 18:43   ` Ihor Radchenko
  2024-02-19 10:05     ` Ihor Radchenko
  2024-02-19 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-01-16 18:43 UTC (permalink / raw)
  To: Jim Porter; +Cc: 68509

Jim Porter <jporterbugs@gmail.com> writes:

> This isn't an issue with 'pcase-dolist', but rather a known/intentional 
> limitation of 'pcase-let':
>
> (pcase-let ((`(,(and (pred stringp) a) .
>                 ,(and (pred stringp) b))
>               '("TODO")))
>    (warn "%S :: %S" a b))
>    -> Warning (emacs): "TODO" :: nil
>
> The 'pcase-let' docstring says this:
>
>> Each EXP should match (i.e. be of compatible structure) to its
>> respective PATTERN; a mismatch may signal an error or may go
>> undetected, binding variables to arbitrary values, such as nil.
>
> I do think we should fix it somehow though. This behavior is extremely 
> confusing, and as much as I'm a fan of 'pcase', I'm emphatically *not* a 
> fan of how this part works.

Not sure about pcase-let, but pcase-dolist specifically may be
simplified not to use pcase-let:

(if (pcase--trivial-upat-p (car spec))
      `(dolist ,spec ,@body)
    (let ((tmpvar (gensym "x")))
      `(dolist (,tmpvar ,@(cdr spec))
         (pcase ,tmpvar (,(car spec) ,@body)))))

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-01-16 18:43   ` Ihor Radchenko
@ 2024-02-19 10:05     ` Ihor Radchenko
  2024-02-19 12:59       ` Eli Zaretskii
  2024-02-19 15:53       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-19 10:05 UTC (permalink / raw)
  To: Jim Porter; +Cc: 68509

[-- Attachment #1: Type: text/plain, Size: 434 bytes --]

Ihor Radchenko <yantar92@posteo.net> writes:

> Not sure about pcase-let, but pcase-dolist specifically may be
> simplified not to use pcase-let:
>
> (if (pcase--trivial-upat-p (car spec))
>       `(dolist ,spec ,@body)
>     (let ((tmpvar (gensym "x")))
>       `(dolist (,tmpvar ,@(cdr spec))
>          (pcase ,tmpvar (,(car spec) ,@body)))))

See the attached patch.
If the patch is acceptable, we also need to update the manual.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-pcase-let-Skip-LIST-element-that-do-not-match-the-PA.patch --]
[-- Type: text/x-patch, Size: 3056 bytes --]

From f3e1362f7687c731e0ba4e410f005252309ffc3f Mon Sep 17 00:00:00 2001
Message-ID: <f3e1362f7687c731e0ba4e410f005252309ffc3f.1708337064.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Mon, 19 Feb 2024 13:02:21 +0300
Subject: [PATCH] pcase-let: Skip LIST element that do not match the PATTERN
 (bug#68509)

* lisp/emacs-lisp/pcase.el (pcase-dolist): Use `pcase' rather than
`pcase-let*' to match the list elements.  Update the docstring,
describing the behavior when list elements to not match the pattern.
The previous undefined behavior is removed.
* test/lisp/emacs-lisp/pcase-tests.el (pcase-tests-pcase-dolist): Add
new test.
---
 lisp/emacs-lisp/pcase.el            | 13 ++++++-------
 test/lisp/emacs-lisp/pcase-tests.el | 12 ++++++++++++
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index ae9bd87997c..8dc11b20a6f 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -329,21 +329,20 @@ pcase-let
 (defmacro pcase-dolist (spec &rest body)
   "Eval BODY once for each set of bindings defined by PATTERN and LIST elements.
 PATTERN should be a `pcase' pattern describing the structure of
-LIST elements, and LIST is a list of objects that match PATTERN,
-i.e. have a structure that is compatible with PATTERN.
+LIST elements, and LIST is a list of objects.
 For each element of LIST, this macro binds the variables in
 PATTERN to the corresponding subfields of the LIST element, and
-then evaluates BODY with these bindings in effect.  The
-destructuring bindings of variables in PATTERN to the subfields
-of the elements of LIST is performed as if by `pcase-let'.
+then evaluates BODY with these bindings in effect.  When an element does
+not match the pattern, such element is skipped.
+The destructuring bindings of variables in PATTERN to the subfields
+of the elements of LIST is performed as if by `pcase'.
 \n(fn (PATTERN LIST) BODY...)"
   (declare (indent 1) (debug ((pcase-PAT form) body)))
   (if (pcase--trivial-upat-p (car spec))
       `(dolist ,spec ,@body)
     (let ((tmpvar (gensym "x")))
       `(dolist (,tmpvar ,@(cdr spec))
-         (pcase-let* ((,(car spec) ,tmpvar))
-           ,@body)))))
+	 (pcase ,tmpvar (,(car spec) ,@body))))))
 
 ;;;###autoload
 (defmacro pcase-setq (pat val &rest args)
diff --git a/test/lisp/emacs-lisp/pcase-tests.el b/test/lisp/emacs-lisp/pcase-tests.el
index d062965952a..241729c108a 100644
--- a/test/lisp/emacs-lisp/pcase-tests.el
+++ b/test/lisp/emacs-lisp/pcase-tests.el
@@ -160,4 +160,16 @@ pcase-tests-setq
   (should-error (pcase-setq a)
                 :type '(wrong-number-of-arguments)))
 
+(ert-deftest pcase-tests-pcase-dolist ()
+  ;; Ignore non-matching elements.
+  (should
+   (equal
+    '(("DONE" . "a"))
+    (let (result)
+      (pcase-dolist (`(,(and (pred stringp) a) .
+		       ,(and (pred stringp) b))
+	             '(("TODO") ("DONE" . "a")))
+        (push (cons a b) result))
+      (nreverse result)))))
+
 ;;; pcase-tests.el ends here.
-- 
2.43.0


[-- Attachment #3: Type: text/plain, Size: 224 bytes --]


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-19 10:05     ` Ihor Radchenko
@ 2024-02-19 12:59       ` Eli Zaretskii
  2024-02-19 15:53       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 21+ messages in thread
From: Eli Zaretskii @ 2024-02-19 12:59 UTC (permalink / raw)
  To: Ihor Radchenko, Stefan Monnier; +Cc: jporterbugs, 68509

> Cc: 68509@debbugs.gnu.org
> From: Ihor Radchenko <yantar92@posteo.net>
> Date: Mon, 19 Feb 2024 10:05:33 +0000
> 
> Ihor Radchenko <yantar92@posteo.net> writes:
> 
> > Not sure about pcase-let, but pcase-dolist specifically may be
> > simplified not to use pcase-let:
> >
> > (if (pcase--trivial-upat-p (car spec))
> >       `(dolist ,spec ,@body)
> >     (let ((tmpvar (gensym "x")))
> >       `(dolist (,tmpvar ,@(cdr spec))
> >          (pcase ,tmpvar (,(car spec) ,@body)))))
> 
> See the attached patch.
> If the patch is acceptable, we also need to update the manual.

Thanks.  Adding Stefan to the discussion.





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-01-16 16:52 ` Jim Porter
  2024-01-16 18:43   ` Ihor Radchenko
@ 2024-02-19 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-19 18:16     ` Ihor Radchenko
  1 sibling, 1 reply; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-19 15:51 UTC (permalink / raw)
  To: Jim Porter; +Cc: Ihor Radchenko, 68509

>> Consider the following
>> (pcase-dolist (`(,(and (pred stringp) a) .
>> 		 ,(and (pred stringp) b))
>> 	       '(("TODO") ("DONE" . "a")))
>>    (warn "%S :: %S" a b))
>> Executing the above yields
>> ⛔ Warning (emacs): "TODO" :: nil
>> ⛔ Warning (emacs): "DONE" :: "a"
>> even though ("TODO") does not match the pattern.
>
> This isn't an issue with 'pcase-dolist', but rather a known/intentional
> limitation of 'pcase-let':

Indeed, I consider the above a pilot error.
`pcase-dolist` and `pcase-let` use Pcase patterns to do *destructuring*,
which is a different task than the one done by `pcase` (which decides
whether a value matches a pattern or not).

>> Each EXP should match (i.e. be of compatible structure) to its
>> respective PATTERN; a mismatch may signal an error or may go
>> undetected, binding variables to arbitrary values, such as nil.
> I do think we should fix it somehow though.  This behavior is
> extremely confusing, and as much as I'm a fan of 'pcase', I'm
> emphatically *not* a fan of how this part works.

I'm quite happy with the way it works when you use it as intended.
But I'm not really satisfied either with the way it behaves when the
coder doesn't understand its semantics, nor about the way we document
that semantics.

The difficulty in resolving this can be illustrated with the following
pattern:

    `(a . ,b)

This pattern leads to two tests: (consp VAL) and (eq 'a (car VAL)).
When destructuring, we want to throw away both tests (we want to throw
away most tests, except those needed to choose between two `or`
branches).

We could decide to emit a warning because we silently skip
the `eq` test, which would help the coders understand that the pattern
doesn't do what they think.
But emitting that same warning because we silently skip the `consp` test
would be really annoying because rewriting the pattern to avoid this
is impractical.

For a human, it's pretty easy to distinguish those two cases.  But it's
difficult to provide a precise definition that distinguishes those two cases.

We could also keep the tests and emit a warning or even an error when
they fail, but if that's the behavior you want, then you should
arguably use `pcase(-exhaustive)` instead.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-19 10:05     ` Ihor Radchenko
  2024-02-19 12:59       ` Eli Zaretskii
@ 2024-02-19 15:53       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-19 18:14         ` Ihor Radchenko
  1 sibling, 1 reply; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-19 15:53 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

> * lisp/emacs-lisp/pcase.el (pcase-dolist): Use `pcase' rather than
> `pcase-let*' to match the list elements.  Update the docstring,

That changes its behavior.  It *will* break code.
This is basically not the same macro any more.  Instead of being a macro
that iterates over all the elements of the list, it becomes a macro
which iterates only over the matching elements.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-19 15:53       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-02-19 18:14         ` Ihor Radchenko
  2024-02-20  2:41           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-19 18:14 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jim Porter, 68509

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> * lisp/emacs-lisp/pcase.el (pcase-dolist): Use `pcase' rather than
>> `pcase-let*' to match the list elements.  Update the docstring,
>
> That changes its behavior.  It *will* break code.
> This is basically not the same macro any more.  Instead of being a macro
> that iterates over all the elements of the list, it becomes a macro
> which iterates only over the matching elements.

Currently, the docstring states:

    PATTERN should be a `pcase' pattern describing the structure of
    LIST elements, and LIST is a list of objects that match PATTERN,
    i.e. have a structure that is compatible with PATTERN.

It is undefined what happens when LIST objects do not match PATTERN.

So, any code relying upon iterating over non-matching elements is
relying upon undefined, undocumented behaviour.

Moreover, current implementation binds /partially matching/ list
elements, which is even more fragile. From `pcase-let' docstring:

    a mismatch may signal an error or may go
    undetected, binding variables to arbitrary values, such as nil.

What I suggest is to change what happens when PATTERN does not much more
explicitly.

In my patch, I proposed to skip such elements.
An alternative could be throwing an error.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-19 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-02-19 18:16     ` Ihor Radchenko
  2024-02-20  2:46       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-19 18:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jim Porter, 68509

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> The difficulty in resolving this can be illustrated with the following
> pattern:
>
>     `(a . ,b)
>
> This pattern leads to two tests: (consp VAL) and (eq 'a (car VAL)).
> When destructuring, we want to throw away both tests (we want to throw
> away most tests, except those needed to choose between two `or`
> branches).
>
> We could decide to emit a warning because we silently skip
> the `eq` test, which would help the coders understand that the pattern
> doesn't do what they think.
> But emitting that same warning because we silently skip the `consp` test
> would be really annoying because rewriting the pattern to avoid this
> is impractical.

May you please elaborate how this example is related to destructuring
from user perspective? It appears to me that you are talking about
implementation details of `pcase', which are elusive to me.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-19 18:14         ` Ihor Radchenko
@ 2024-02-20  2:41           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-20 13:40             ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-20  2:41 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

Ihor Radchenko [2024-02-19 18:14:24] wrote:

> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>
>>> * lisp/emacs-lisp/pcase.el (pcase-dolist): Use `pcase' rather than
>>> `pcase-let*' to match the list elements.  Update the docstring,
>>
>> That changes its behavior.  It *will* break code.
>> This is basically not the same macro any more.  Instead of being a macro
>> that iterates over all the elements of the list, it becomes a macro
>> which iterates only over the matching elements.
>
> Currently, the docstring states:
>
>     PATTERN should be a `pcase' pattern describing the structure of
>     LIST elements, and LIST is a list of objects that match PATTERN,
>     i.e. have a structure that is compatible with PATTERN.

The doc for `pcase-let` is a bit more precise:

    Each EXP should match (i.e. be of compatible structure) to its
    respective PATTERN; a mismatch may signal an error or may go
    undetected, binding variables to arbitrary values, such as nil.

> In my patch, I proposed to skip such elements.
> An alternative could be throwing an error.

As I said, what you propose is a *different* construct.
Maybe we should add some extra option/keyword to `pcase-dolist` to
indicate what to do with elements that don't match (such as signaling
an error, a warning, silently skipping it, ...).

Similar issues affect `pcase-let`, of course.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-19 18:16     ` Ihor Radchenko
@ 2024-02-20  2:46       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-20  2:46 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

>> The difficulty in resolving this can be illustrated with the following
>> pattern:
>>
>>     `(a . ,b)
>>
>> This pattern leads to two tests: (consp VAL) and (eq 'a (car VAL)).
>> When destructuring, we want to throw away both tests (we want to throw
>> away most tests, except those needed to choose between two `or`
>> branches).
>>
>> We could decide to emit a warning because we silently skip
>> the `eq` test, which would help the coders understand that the pattern
>> doesn't do what they think.
>> But emitting that same warning because we silently skip the `consp` test
>> would be really annoying because rewriting the pattern to avoid this
>> is impractical.
>
> May you please elaborate how this example is related to destructuring
> from user perspective? It appears to me that you are talking about
> implementation details of `pcase', which are elusive to me.

I'm just reading aloud what the `(a . ,b) pattern means: it means "VAL
has to be a cons, and its car should be equal to `a`" (and in addition
to that, we'll extract the `cdr` and put it into the `b` variable).

We might want to warn the user that such a pattern in `pcase-let` and
`pcase-dolist` is probably an error because the `a` won't actually be
checked, so it will behave just like the `(,_ . ,b) pattern.

But warning the user that the `consp` check will also be dropped would
be annoying because it's not like the users can easily write a different
pattern that still behaves the same but does not imply such
a `consp` check.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-20  2:41           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-02-20 13:40             ` Ihor Radchenko
  2024-02-20 14:35               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-20 13:40 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jim Porter, 68509

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> In my patch, I proposed to skip such elements.
>> An alternative could be throwing an error.
>
> As I said, what you propose is a *different* construct.
> Maybe we should add some extra option/keyword to `pcase-dolist` to
> indicate what to do with elements that don't match (such as signaling
> an error, a warning, silently skipping it, ...).
>
> Similar issues affect `pcase-let`, of course.

What about adding extra option/keyword and also showing a runtime
warning when pcase-dolist/pcase-let encounter something that does not
match the pattern? In such situation, the code logic probably has a
problem that is worth highlighting.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-20 13:40             ` Ihor Radchenko
@ 2024-02-20 14:35               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-20 15:16                 ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-20 14:35 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

> What about adding extra option/keyword and also showing a runtime
> warning when pcase-dolist/pcase-let encounter something that does not
> match the pattern?

In the current use of those primitives, it's routine/normal/common for
a pattern like `(,a ,b) to encounter lists of different length than 2,
so a warning should be emitted only if specifically requested via an
option/keyword.

I think it would be OK to emit a warning (even if not specifically
requested via an option/keyword) when a value like (help . me) fails to
match `(a . ,b), but as mentioned I don't know a good way to distinguish
those two kinds of cases.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-20 14:35               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-02-20 15:16                 ` Ihor Radchenko
  2024-02-20 17:51                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-20 15:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jim Porter, 68509

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> What about adding extra option/keyword and also showing a runtime
>> warning when pcase-dolist/pcase-let encounter something that does not
>> match the pattern?
>
> In the current use of those primitives, it's routine/normal/common for
> a pattern like `(,a ,b) to encounter lists of different length than 2,
> so a warning should be emitted only if specifically requested via an
> option/keyword.

But isn't it undocumented?

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-20 15:16                 ` Ihor Radchenko
@ 2024-02-20 17:51                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-21 11:23                     ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-20 17:51 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

>>> What about adding extra option/keyword and also showing a runtime
>>> warning when pcase-dolist/pcase-let encounter something that does not
>>> match the pattern?
>> In the current use of those primitives, it's routine/normal/common for
>> a pattern like `(,a ,b) to encounter lists of different length than 2,
>> so a warning should be emitted only if specifically requested via an
>> option/keyword.
> But isn't it undocumented?

AFAIK the "best" documentation we have for that is the one in
`pcase-let`, which is indeed unsatisfactory.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-20 17:51                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-02-21 11:23                     ` Ihor Radchenko
  2024-02-21 14:17                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-21 11:23 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jim Porter, 68509

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>>> In the current use of those primitives, it's routine/normal/common for
>>> a pattern like `(,a ,b) to encounter lists of different length than 2,
>>> so a warning should be emitted only if specifically requested via an
>>> option/keyword.
>> But isn't it undocumented?
>
> AFAIK the "best" documentation we have for that is the one in
> `pcase-let`, which is indeed unsatisfactory.

May you then describe in more details what is the intended behavior when
PATTERN does not match VALUE in destructuring?

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-21 11:23                     ` Ihor Radchenko
@ 2024-02-21 14:17                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-23 14:05                         ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-21 14:17 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

>>>> In the current use of those primitives, it's routine/normal/common for
>>>> a pattern like `(,a ,b) to encounter lists of different length than 2,
>>>> so a warning should be emitted only if specifically requested via an
>>>> option/keyword.
>>> But isn't it undocumented?
>>
>> AFAIK the "best" documentation we have for that is the one in
>> `pcase-let`, which is indeed unsatisfactory.
>
> May you then describe in more details what is the intended behavior when
> PATTERN does not match VALUE in destructuring?

How 'bout the patch below?


        Stefan


diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 78ad5b68a51..cf60cabe52b 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -1317,11 +1317,18 @@ Destructuring with pcase Patterns
 does the same as the previous example, except that it directly tries
 to extract @code{x} and @code{y} from @code{my-list} without first
 verifying if @code{my-list} is a list which has the right number of
-elements and has @code{add} as its first element.  The precise
-behavior when the object does not actually match the pattern is
-undefined, although the body will not be silently skipped: either an
-error is signaled or the body is run with some of the variables
-potentially bound to arbitrary values like @code{nil}.
+elements and has @code{add} as its first element.
+
+The precise behavior when the object does not actually match the pattern
+depends on the types, although the body will not be silently skipped:
+either an error is signaled or the body is run with some of the
+variables bound to arbitrary values like @code{nil}.
+For example, the above pattern will result in @var{x} and @var{y}
+being extracted with operations like @code{car} or @code{nth}, so they
+will get value @code{nil} when @var{my-list} is too short.  In contrast,
+with a pattern like @code{`[add ,x ,y]}, those same variables would
+be extracted using @code{aref} which would signal an error if
+@var{my-list} is not an array or is too short.
 
 The pcase patterns that are useful for destructuring bindings are
 generally those described in @ref{Backquote Patterns}, since they






^ permalink raw reply related	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-21 14:17                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-02-23 14:05                         ` Ihor Radchenko
  2024-02-23 14:58                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-23 14:05 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jim Porter, 68509

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> May you then describe in more details what is the intended behavior when
>> PATTERN does not match VALUE in destructuring?
>
> How 'bout the patch below?
> ...
> +The precise behavior when the object does not actually match the pattern
> +depends on the types, although the body will not be silently skipped:
> +either an error is signaled or the body is run with some of the
> +variables bound to arbitrary values like @code{nil}.
> +For example, the above pattern will result in @var{x} and @var{y}
> +being extracted with operations like @code{car} or @code{nth}, so they
> +will get value @code{nil} when @var{my-list} is too short.  In contrast,
> +with a pattern like @code{`[add ,x ,y]}, those same variables would
> +be extracted using @code{aref} which would signal an error if
> +@var{my-list} is not an array or is too short.

This is confusing. In particular, "for example" implies that other
situations are possible. It is unclear how the reader will know when
"variables bound to arbitrary values" happen, when variables are bound
to nil, and when an error is signaled.

I would re-structure the paragraph, explicitly listing the possible
outcomes when the PATTERN does not match VALUE and stating that any
other non-matching PATTERN will lead to undefined outcome.

Also, with the current behavior of `pcase-let', it appears to be
impossible to distinguish between too short list (1 2 3) and
(1 2 3 nil nil) when assigning destructuring pattern.


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-23 14:05                         ` Ihor Radchenko
@ 2024-02-23 14:58                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-24 13:28                             ` Ihor Radchenko
  0 siblings, 1 reply; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-23 14:58 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

>> How 'bout the patch below?
>> ...
>> +The precise behavior when the object does not actually match the pattern
>> +depends on the types, although the body will not be silently skipped:
                   ^^^^^
                  pattern

>> +either an error is signaled or the body is run with some of the
>> +variables bound to arbitrary values like @code{nil}.
>> +For example, the above pattern will result in @var{x} and @var{y}
>> +being extracted with operations like @code{car} or @code{nth}, so they
>> +will get value @code{nil} when @var{my-list} is too short.  In contrast,
>> +with a pattern like @code{`[add ,x ,y]}, those same variables would
>> +be extracted using @code{aref} which would signal an error if
>> +@var{my-list} is not an array or is too short.
>
> This is confusing. In particular, "for example" implies that other
> situations are possible. It is unclear how the reader will know when
> "variables bound to arbitrary values" happen, when variables are bound
> to nil, and when an error is signaled.

This part of the doc is generic, so it can't guarantee anything: the
behavior depends on the actual pattern and the way that pattern is defined.
In order to intuit what will happen, the reader needs to guess which
primitives are used to extract the info from value (e.g. `car/cdr/nth`
for cons cells, `aref` for arrays, ...).

> I would re-structure the paragraph, explicitly listing the possible
> outcomes when the PATTERN does not match VALUE and stating that any
> other non-matching PATTERN will lead to undefined outcome.

Could you try to do that?
[ I've found back-and-forth modifications of docs give better results
  than single-sided writing.  ]

> Also, with the current behavior of `pcase-let', it appears to be
> impossible to distinguish between too short list (1 2 3) and
> (1 2 3 nil nil) when assigning destructuring pattern.

Destructuring  by definition can't do "distinguish", so that's not a big
surprise 🙂

But of course, this isn't really true, you can do:

    (pcase-let ((`(,x ,y ,z . ,tail) FOO))
      (if (equal tail '(nil nil))
          ...
        ...))

or you can get hairy and do things like:

    (pcase-let (((or `(,x ,y ,z ,a ,_)
                     (and `(,x ,y ,z) (let a 'shortorlonglist)))
                 FOO))
      (if (eq a 'shortorlonglist)
          ...
        ...))

but that kind if Pcase pattern, while possible, is rarely worth the trouble.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-23 14:58                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-02-24 13:28                             ` Ihor Radchenko
  2024-02-24 14:57                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 21+ messages in thread
From: Ihor Radchenko @ 2024-02-24 13:28 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jim Porter, 68509

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>>> +For example, the above pattern will result in...
>>
>> This is confusing. In particular, "for example" implies that other
>> situations are possible. It is unclear how the reader will know when
>> "variables bound to arbitrary values" happen, when variables are bound
>> to nil, and when an error is signaled.
>
> This part of the doc is generic, so it can't guarantee anything: the
> behavior depends on the actual pattern and the way that pattern is defined.
> In order to intuit what will happen, the reader needs to guess which
> primitives are used to extract the info from value (e.g. `car/cdr/nth`
> for cons cells, `aref` for arrays, ...).

I do not think that "guess" is what we should ever put into docs.
Because implementation details may change and any kind of guess may then
go wrong.

>> I would re-structure the paragraph, explicitly listing the possible
>> outcomes when the PATTERN does not match VALUE and stating that any
>> other non-matching PATTERN will lead to undefined outcome.
>
> Could you try to do that?
> [ I've found back-and-forth modifications of docs give better results
>   than single-sided writing.  ]

I could, but I am not sure which non-matching outcomes we should
document and which we want to leave undefined.

I still don't have a clear picture about the differences between normal
pcase and destructuring pcase. Especially for non-trivial patterns.
For example,

(pcase-let (((and `(,a ,b ,c) (guard (eq a 'foo))) '(bar a)))
  (list a b c)) ; =>'(bar a nil)

is extremely confusing.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 21+ messages in thread

* bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly
  2024-02-24 13:28                             ` Ihor Radchenko
@ 2024-02-24 14:57                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 21+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-24 14:57 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Jim Porter, 68509

>> Could you try to do that?
>> [ I've found back-and-forth modifications of docs give better results
>>   than single-sided writing.  ]
>
> I could, but I am not sure which non-matching outcomes we should
> document and which we want to leave undefined.

Try your best.  Then I'll try to improve it, then you'll try to improve it...

> I still don't have a clear picture about the differences between normal
> pcase and destructuring pcase.

The best way to clarify it is by writing what you think happens.
Don't worry about the risk that what you write is "wrong", because
that's the part I can easily catch and fix.


        Stefan






^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2024-02-24 14:57 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-16 15:07 bug#68509: 30.0.50; pcase-dolist matches backquote pattern incorrectly Ihor Radchenko
2024-01-16 16:52 ` Jim Porter
2024-01-16 18:43   ` Ihor Radchenko
2024-02-19 10:05     ` Ihor Radchenko
2024-02-19 12:59       ` Eli Zaretskii
2024-02-19 15:53       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-19 18:14         ` Ihor Radchenko
2024-02-20  2:41           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-20 13:40             ` Ihor Radchenko
2024-02-20 14:35               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-20 15:16                 ` Ihor Radchenko
2024-02-20 17:51                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-21 11:23                     ` Ihor Radchenko
2024-02-21 14:17                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-23 14:05                         ` Ihor Radchenko
2024-02-23 14:58                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-24 13:28                             ` Ihor Radchenko
2024-02-24 14:57                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-19 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-19 18:16     ` Ihor Radchenko
2024-02-20  2:46       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).