Hi,

Thanks for your reply!

Le 16 août 2020 à 22:41, Guido van Rossum <guido@python.org> a écrit :

On Sun, Aug 16, 2020 at 12:37 PM Jean Abou Samra <jean@abou-samra.fr> wrote:
Hi there,

As a poor user, I am extremely excited about the possibilities PEP 622 (structural pattern matching) opens. I'd like to ask a few questions.

I hope these were not already answered in other threads, which it is hard to follow given the amounts of information.

Most of the threads can hardly be considered information -- at best it's debate, arguments and opinions. :-)

You're entirely right.

 
First, I'd like to know wether walrus patterns are encouraged as an expressive way to explain the code in addition to comments, for example:

match number:
  case exact := numbers.Rational():
      ...
  case inexact:
      ...

Here we rename number depending on the case clause that was taken. Would this be considered good practice? Maybe it'd be worth codifying in PEP 8 if PEP 622 is accepted?

I think we should wait a while to see what style develops before recommending specifics. Right now I'm not excited about it, mostly because the first case is a lot longer. Assuming the code blocks in the cases aren't very long, it doesn't seem hard to keep the context ("is the number exact or inexact here?") in mind without using the different variable names.

I recognise that my example was somehow too trivial; it would likely look more natural when rewriting visitors, where you could end up with a lot of code in each case clause. For instance, if I had to rewrite
https://github.com/sympy/sympy/blob/c3087c883be02ad228820ff714ad6eb9af1ad868/sympy/parsing/ast_parser.py
I may write: case num := Num(), etc.

(By the way, if you read sympy_parser.py in the same directory, it's full of examples where pattern matching would be useful.)

I also noticed this in the PEP, under "Capture patterns":

match greeting:
    case "":
        print("Hello!")
    case name:
        print(f"Hi {name}!")

Anyway, I agree that the best way forward is to wait and see what usage patterns develop (no pun intended).

A nit: how is the keywords module going to integrate soft keywords? Perhaps not at all?

Already taken care of -- it has a separate list `softkwlist` (currently empty) and corresponding function `issoftkeyword`. If any soft keywords appear in the grammar the code generation process will update keyword.py.


My bad, I should have checked out the dev documentation since the PEG parser is a novelty...

Also, I see potential for a caveat:

match number:
  case int: # missing parentheses!
      ...
  case float:
      ...
  case Fraction:
      ...

In this case, if I understand the specification correctly, the first case will always match, right? Maybe the interpreter could throw a SyntaxWarning when a bare capture pattern (without a guard) is used as a pattern in any case clause other than the last one? As far as I understand, this could possibly prevent many of the mistakes in load/store that people have been rightfully complaining about so far. It's merely a stronger measure than letting static checkers do the work (since we don't all use these tools).

The reference implementation in fact does issue a SyntaxWarning for this case.

Good! (Sorry, I couldn't check that as mybinder.org currently seems unavailable... :-( ).
 
Finally, was as-based syntax considered as an alternative to walrus patterns, that is, PATTERN as NAME instead of NAME := PATTERN, as we have in the try statement? Given the extensive discussion, I guess it might have been rejected, so it could deserve a place under "Rejected ideas" -- this holds for all the above too, which I'm sorry about if it's dumb.

I don't recall it was discussed. A very early draft (that wasn't published) used `as` instead of `case`, and that draft used `:=` for this purpose. It's always made sense to use that, so I've never considered `as`. Do you think there are situations where `as` has a clear advantage over `:=`?

Let's see: it probably avoids some uglinesses that occur with the use of = in class patterns.

case Expr(value=(add := BinOp(op=Add()))):
vs.
case Expr(value=(BinOp(op=Add()) as add))

There is also
case Line(start := Point(x, y), end):
which might be confused with
case Line(start=Point(x, y), end):

However, the main reason why I was asking is that 'as' parallels well with the current context that is closest to pattern matching, namely the try statement. The walrus parallels with assignment expressions, so this is in fact a story of wether patterns should look more like expressions or the LHS of an assignment, as I see it.

The walrus highlights the structure that you're trying to fit in: "This is an Expr, having as a value an addition, which looks like ...". By contrast, having the name after the pattern makes you think like the interpreter: "Try to fit this into BinOp(op=Add()), and if that succeds, put it in 'add'." Both are defendable. I think the latter would be a little easier to teach, so I'd encourage considering it.

Best,
Jean Abou Samra