Mailing List Archive

PEP 622 version 2 (Structural Pattern Matching)
Today I’m happy (and a little trepidatious) to announce the next
version of PEP 622, Pattern Matching. As authors we welcome Daniel F
Moisset in our midst. Daniel wrote a lot of the new text in this
version, which introduces the subject matter much more gently than the
first version did. He also convinced us to drop the `__match__`
protocol for now: the proposal stands quite well without that kind of
extensibility, and postponing it will allow us to design it at a later
time when we have more experience with how `match` is being used.

That said, the new version does not differ dramatically in what we
propose. Apart from dropping `__match__` we’re dropping the leading
dot to mark named constants, without a replacement, and everything
else looks like we’re digging in our heels. Why is that? Given the
firestorm of feedback we received and the numerous proposals (still
coming) for alternative syntax, it seems a bad tactic not to give up
something more substantial in order to get this proposal passed. Let
me explain.

Language design is not like politics. It’s not like mathematics
either, but I don’t think this situation is at all similar to
negotiating a higher minimum wage in exchange for a lower pension,
where you can definitely argue about exactly how much lower/higher
you’re willing to go. So I don’t think it’s right to propose making
the feature a little bit uglier just to get it accepted.

Frankly, 90% of the issue is about what among the authors we’ve dubbed
the “load/store” problem (although Tobias never tires to explain that
the “load” part is really “load-and-compare”). There’s a considerable
section devoted to this topic in the PEP, but I’d like to give it
another try here.

In case you’ve been avoiding python-dev lately, the problem is
this. Pattern matching lets you capture values from the subject,
similar to sequence unpacking, so that you can write for example
```
x = range(4)
match x:
case (a, b, *rest):
print(f"first={a}, second={b}, rest={rest}") # 0, 1, [2, 3]
```
Here the `case` line captures the contents of the subject `x` in three
variables named `a`, `b` and `rest`. This is easy to understand by
pretending that a pattern (i.e., what follows `case`) is like the LHS
of an assignment.

However, in order to make pattern matching more useful and versatile,
the pattern matching syntax also allows using literals instead of
capture variables. This is really handy when you want to distinguish
different cases based on some value, for example
```
match t:
case ("rect", real, imag):
return complex(real, imag)
case ("polar", r, phi):
return complex(r * cos(phi), r * sin(phi))
```
You might not even notice anything funny here if I didn’t point out
that `"rect"` and `"polar"` are literals -- it’s really quite
natural for patterns to support this once you think about it.

The problem that everybody’s been concerned about is that Python
programmers, like C programmers before them, aren’t too keen to have
literals like this all over their code, and would rather give names to
the literals, for example
```
USE_POLAR = "polar"
USE_RECT = "rect"
```
Now we would like to be able to replace those literals with the
corresponding names throughout our code and have everything work like
before:
```
match t:
case (USE_RECT, real, imag):
return complex(real, imag)
case (USE_POLAR, r, phi):
return complex(r * cos(phi), r * sin(phi))
```
Alas, the compiler doesn’t know that we want `USE_RECT` to be a
constant value to be matched while we intend `real` and `imag` to be
variables to be given the corresponding values captured from the
subject. So various clever ways have been proposed to distinguish the
two cases.

This discussion is not new to the authors: before we ever published
the first version of the PEP we vigorously debated this (it is Issue 1
in our tracker!), and other languages before us have also had to come
to grips with it. Even many statically compiled languages! The reason
is that for reasons of usability it’s usually deemed important that
their equivalent of `case` auto-declare the captured variables, and
variable declarations may hide (override) like-named variables in
outer scopes.

Scala, for example, uses several different rules: first, capture
variable names must start with a lowercase letter (so it would
handle the above example as intended); next, capture variables
cannot be dotted names (like `mod.var`); finally, you can enclose any
variable in backticks to force the compiler to see it as a load
instead of a store. Elixir uses another form of markup for loads: `x`
is a capture variable, but `^x` loads and compares the value of `x`.

There are a number of dead ends when looking for a solution that works
for Python. Checking at runtime whether a name is defined or not is
one of these: there are numerous reasons why this could be confusing,
not the least of which being that the `match` may be executed in a
loop and the variable may already be bound by a previous
iteration. (True, this has to do with the scope we’ve adopted for
capture variables. But believe me, giving each case clause its own
scope is quite horrible by itself, and there are other
action-at-a-distance effects that are equally bad.)

It’s been proposed to explicitly state the names of the variables
bound in a header of the `match` statement; but this doesn’t scale
when the number of cases becomes larger, and requires users to do
bookkeeping the compiler should be able to do. We’re really looking
for a solution that tells you when you’re looking at an individual
`case` which variables are captured and which are used for
load-and-compare.

Marking up the capture variables with some sigil (e.g. `$x` or `x?`)
or other markup (e.g. backticks or `<x>`) makes this common case ugly
and inconsistent: it’s unpleasant to see for example
```
case %x, %y:
print(x, y)
```
No other language we’ve surveyed uses special markup for capture
variables; some use special markup for load-and-compare, so we’ve
explored this. In fact, in version 1 of the PEP our long-debated
solution was to use a leading dot. This was however boohed off the
field, so for version 2 we reconsidered. In the end nothing struck our
fancy (if `.x` is unacceptable, it’s unclear why `^x` would be any
better), and we chose a simpler rule: named constants are only
recognized when referenced via some namespace, such as `mod.var` or
`Color.RED`.

We believe it’s acceptable that things looking like `mod.var` are
never considered capture variables -- the common use cases for `match`
are such that one would almost never want to capture into a different
namespace. (Just like you very rarely see `for self.i in …` and never
`except E as scope.var` -- the latter is illegal syntax and sets a
precedent.)

One author would dearly have seen Scala’s uppercase rule adopted, but
in the end was convinced by the others that this was a bad idea, both
because there’s no precedent in Python’s syntax, and because many
human languages simply don’t make the distinction between lowercase
and uppercase in their writing systems.

So what should you do if you have a local variable (say, a function
argument) that you want to use as a value in a pattern? One solution
is to capture the value in another variable and use a guard to compare
that variable to the argument:
```
def foo(x, spam):
match x:
case Point(p, q, context=c) if c == spam:
# Match
```
If this really is a deal-breaker after all other issues have been
settled, we could go back to considering some special markup for
load-and-compare of simple names (even though we expect this case to
be very rare). But there’s no pressing need to decide to do this now
-- we can always add new markup for this purpose in a future version,
as long as we continue to support dotted names without markup,
since that *is* a commonly needed case.

There’s one other issue where in the end we could be convinced to
compromise: whether to add an `else` clause in addition to `case
_`. In fact, we probably would already have added it, except for one
detail: it’s unclear whether the `else` should be aligned with `case`
or `match`. If we are to add this we would have to ask the Steering
Council to decide for us, as the authors deadlocked on this question.

Regarding the syntax for wildcards and OR patterns, the PEP explains
why `_` and `|` are the best choices here: no other language surveyed
uses anything but `_` for wildcards, and the vast majority uses `|`
for OR patterns. A similar argument applies to class patterns.

If you've made it so far, here are the links to check out, with an
open mind. As a reminder, the introductory sections (Abstract,
Overview, and Rationale and Goals) have been entirely rewritten and
also serve as introduction and tutorial.

- PEP 622: https://www.python.org/dev/peps/pep-0622/
- Playground:
https://mybinder.org/v2/gh/gvanrossum/patma/master?urlpath=lab/tree/playground-622.ipynb

--
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*
<http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
Thanks for explaining the open issues so well, Guido.

My 2¢ on the `else` matter:

On Wed, Jul 8, 2020 at 12:05 PM Guido van Rossum <guido@python.org> wrote:
> [...] it’s unclear whether the `else` should be aligned with `case`
> or `match`.

I strongly favor the option of aligning the `else` clause with
`match`, because `else` is a special clause therefore it should look
special.

"Designers need to ensure that controls and displays for different
purposes are significantly different from one another."
—Donald Norman, The Design of Everyday Things

As I first read a `match` statement, and I see an `else` clause, I
know for sure that *something* will happen. If no `else` clause is
present, I know it's possible nothing will happen. It's the same thing
with `else` in `if`, `while`, `for`, `try` statements, where the
`else` is aligned with the opening keyword.


Cheers,

Luciano


--
Luciano Ramalho
| Author of Fluent Python (O'Reilly, 2015)
| http://shop.oreilly.com/product/0636920032519.do
| Technical Principal at ThoughtWorks
| Twitter: @ramalhoorg
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/VNFVA3FTTZ7KESBDG5A7PQHSRW7GE2F5/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
[... snip explanation of key sticking points ...]

Thank you for an excellent write-up combining background context with
possible solutions. Now I need to actually read the PEP ;)

TJG

_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/LFURYGIGZUNV6S2YU4KR5LPVRW43NZTT/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 07/08/2020 08:30 AM, Luciano Ramalho wrote:

> As I first read a `match` statement, and I see an `else` clause, I
> know for sure that *something* will happen. If no `else` clause is
> present, I know it's possible nothing will happen. It's the same thing
> with `else` in `if`, `while`, `for`, `try` statements, where the
> `else` is aligned with the opening keyword.

If `else` is added, I agree with aligning with `match`, for the same reasons -- especially if we can nest match statements.

--
~Ethan~
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/PTSQFVVQLYJJ5SOXF2ASRALU6INPRM6D/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 08/07/2020 16:02, Guido van Rossum wrote:
> Today I’m happy (and a little trepidatious) to announce the next
> version of PEP 622, Pattern Matching.

Thank you very much to everyone who has been working on this, it is much
appreciated. I have one suggestion for the text: could the section on
Capture Patterns emphasise that only simple (i.e not dotted) names are
capture patterns? The simplified grammar is (fairly) clear and the
later section on Constant Value Patterns should make it obvious, but
somehow when reading version 1 I still managed to miss it. I was quite
surprised when it was pointed out that

case (point.x, point.y):

wasn't going to do what I expected!

(PS: I'm still pushing for an "else" clause, and I can see arguments for
it going at either indentation level. Since putting the clause at the
wrong level would be a syntax error, I don't see it being a particularly
big issue where it goes.)

--
Rhodri James *-* Kynesim Ltd
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/OZI6TIM6272O5WMSNEL4YQUBTRPUKJ6T/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 07/08/2020 08:02 AM, Guido van Rossum wrote:

> Today I’m happy (and a little trepidatious) to announce the next
> version of PEP 622, Pattern Matching.

All in all I like it a lot!

> As authors we welcome Daniel F
> Moisset in our midst

Welcom, Daniel, and thank you!

> That said, the new version does not differ dramatically in what we
> propose. Apart from dropping `__match__` we’re dropping the leading
> dot to mark named constants,

Excellent!

> without a replacement,

So namespaced variables only... is there a recommendation on handling global() and local() type variables?

The only thing I didn't see addressed was the concern raised by Pablo:

> On 06/25/2020 04:07 PM, Brandt Bucher wrote:
>> Pablo Galindo Salgado wrote:
>>> ...users can do a positional match against the proxy with a name pattern:
>>>
>>> match input:
>>> case datetime.date(dt):
>>> print(f"The date {dt.isoformat()}"
>>>
>>> ...if 'datetime.date' were updated to implement a non-default __match_args__, allowing individual fields to be pulled out of it like this, then the first block would be valid, correct code before the change, but would raise an ImpossibleMatch after the change because 'dt' is not a field in __match_args__. Is this argument misinterpreting something about the PEP or is missing some important detail?
>>
>> Well yeah, it's actually a fair bit worse than you describe. Since dt is matched positionally, it wouldn't raise during matching - it would just succeed as before, but instead binding the year attribute (not the whole object) to the name "dt". So it wouldn't fail until later, when your method call raises a TypeError.

Why is this no longer an issue? My apologies if I missed it in the PEP.

--
~Ethan~


P.S. Thanks for all your hard work! I am very much looking forward to using this.
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/O65RJZG7OOIKIU5PB7KR4UT4KJR6YI4D/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
One microscopic point:

[Guido]
> ...
> (if `.x` is unacceptable, it’s unclear why `^x` would be any
> better),

As Python's self-appointed spokesperson for the elderly, there's one
very clear difference: a leading "." is - literally - one microscopic
point, all but invisible. A leading caret is far easier to see, on a
variety of devices and using a variety of fonts. Indeed, I missed the
leading dot in ".x" in your email the first two times I read that
sentence.

But a caret is harder to type. So here's an off-the-wall idea: use
an ellipsis. If you're still using a maximal-munch lexer, ellipsis
followed by an identifier is currently a syntax error. "...x" is far
easier to see than ".x', easier to type than "^x", and retains the
mnemonic connection that "something is a named load pattern if and
only if it has dots".

"..." is also a mnemonic for "OK, here I want to match ... umm ... let
me think ... I know! A fixed value." ;-)
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/TPTECZKGQY53L7ZKIQOVOXOTMQE6A447/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On Wed, 8 Jul 2020 18:38:12 +0100
Rhodri James <rhodri@kynesim.co.uk> wrote:
> On 08/07/2020 16:02, Guido van Rossum wrote:
> > Today I’m happy (and a little trepidatious) to announce the next
> > version of PEP 622, Pattern Matching.
>
> Thank you very much to everyone who has been working on this, it is much
> appreciated. I have one suggestion for the text: could the section on
> Capture Patterns emphasise that only simple (i.e not dotted) names are
> capture patterns? The simplified grammar is (fairly) clear and the
> later section on Constant Value Patterns should make it obvious, but
> somehow when reading version 1 I still managed to miss it. I was quite
> surprised when it was pointed out that
>
> case (point.x, point.y):
>
> wasn't going to do what I expected!

Why did you expect? It's not clear to me what it should do at all :-)

Regards

Antoine.

_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/KWALLGME2BPIJSSSZVI3THPDL32MU3DI/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On Wed, 8 Jul 2020 at 16:05, Guido van Rossum <guido@python.org> wrote:

> Today I’m happy (and a little trepidatious) to announce the next
> version of PEP 622, Pattern Matching. As authors we welcome Daniel F
> Moisset in our midst. Daniel wrote a lot of the new text in this
> version, which introduces the subject matter much more gently than the
> first version did. He also convinced us to drop the `__match__`
> protocol for now: the proposal stands quite well without that kind of
> extensibility, and postponing it will allow us to design it at a later
> time when we have more experience with how `match` is being used.
>
> That said, the new version does not differ dramatically in what we
> propose. Apart from dropping `__match__` we’re dropping the leading
> dot to mark named constants, without a replacement, and everything
> else looks like we’re digging in our heels. Why is that? Given the
> firestorm of feedback we received and the numerous proposals (still
> coming) for alternative syntax, it seems a bad tactic not to give up
> something more substantial in order to get this proposal passed. Let
> me explain.
>
> Language design is not like politics. It’s not like mathematics
> either, but I don’t think this situation is at all similar to
> negotiating a higher minimum wage in exchange for a lower pension,
> where you can definitely argue about exactly how much lower/higher
> you’re willing to go. So I don’t think it’s right to propose making
> the feature a little bit uglier just to get it accepted.
>
> Frankly, 90% of the issue is about what among the authors we’ve dubbed
> the “load/store” problem (although Tobias never tires to explain that
> the “load” part is really “load-and-compare”). There’s a considerable
> section devoted to this topic in the PEP, but I’d like to give it
> another try here.
>
> In case you’ve been avoiding python-dev lately, the problem is
> this. Pattern matching lets you capture values from the subject,
> similar to sequence unpacking, so that you can write for example
> ```
> x = range(4)
> match x:
> case (a, b, *rest):
> print(f"first={a}, second={b}, rest={rest}") # 0, 1, [2, 3]
> ```
> Here the `case` line captures the contents of the subject `x` in three
> variables named `a`, `b` and `rest`. This is easy to understand by
> pretending that a pattern (i.e., what follows `case`) is like the LHS
> of an assignment.
>
> However, in order to make pattern matching more useful and versatile,
> the pattern matching syntax also allows using literals instead of
> capture variables. This is really handy when you want to distinguish
> different cases based on some value, for example
> ```
> match t:
> case ("rect", real, imag):
> return complex(real, imag)
> case ("polar", r, phi):
> return complex(r * cos(phi), r * sin(phi))
> ```
> You might not even notice anything funny here if I didn’t point out
> that `"rect"` and `"polar"` are literals -- it’s really quite
> natural for patterns to support this once you think about it.
>
> The problem that everybody’s been concerned about is that Python
> programmers, like C programmers before them, aren’t too keen to have
> literals like this all over their code, and would rather give names to
> the literals, for example
> ```
> USE_POLAR = "polar"
> USE_RECT = "rect"
> ```
> Now we would like to be able to replace those literals with the
> corresponding names throughout our code and have everything work like
> before:
> ```
> match t:
> case (USE_RECT, real, imag):
> return complex(real, imag)
> case (USE_POLAR, r, phi):
> return complex(r * cos(phi), r * sin(phi))
> ```
>

Forgive the intrusion, in case this wasn't already mentioned (I only read a
fraction of emails on this), we could say that name enclosed in parenthesis
would mean loading a constant, instead of storing in a variable:

match t:
case ((USE_RECT), real, imag): # matches the constant USE_RECT
literal value
return complex(real, imag)
case (USE_POLAR, r, phi): # the USE_POLAR portion matches anything
and stores in a USE_POLAR variable
return complex(r * cos(phi), r * sin(phi))

Advantages: in Python (and most programming languages), (x) is the same
thing as x. So, no new syntax, or weird symbols, need to be introduced.

But the parser can distinguish (I hope), and guide the match statement
generation to the appropriate behaviour.

Yes, it's more typing, but hopefully the case is uncommon enough that the
extra typing is not a lot of burden.

Yes, it's easy to type USE_RECT when you really meant (USE_RECT).
Hopefully linters can catch this case and warn you.

OK, that's it, I just thought it was worth throwing yet another idea into
the pot :-)

--
Gustavo J. A. M. Carneiro
Gambit Research
"The universe is always one step beyond logic." -- Frank Herbert
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
*facepalm* this is right there in the PEP, already, as one possible
alternative. Apologies for the noise. :-/

On Wed, 8 Jul 2020 at 19:27, Gustavo Carneiro <gjcarneiro@gmail.com> wrote:

>
>
> On Wed, 8 Jul 2020 at 16:05, Guido van Rossum <guido@python.org> wrote:
>
>> Today I’m happy (and a little trepidatious) to announce the next
>> version of PEP 622, Pattern Matching. As authors we welcome Daniel F
>> Moisset in our midst. Daniel wrote a lot of the new text in this
>> version, which introduces the subject matter much more gently than the
>> first version did. He also convinced us to drop the `__match__`
>> protocol for now: the proposal stands quite well without that kind of
>> extensibility, and postponing it will allow us to design it at a later
>> time when we have more experience with how `match` is being used.
>>
>> That said, the new version does not differ dramatically in what we
>> propose. Apart from dropping `__match__` we’re dropping the leading
>> dot to mark named constants, without a replacement, and everything
>> else looks like we’re digging in our heels. Why is that? Given the
>> firestorm of feedback we received and the numerous proposals (still
>> coming) for alternative syntax, it seems a bad tactic not to give up
>> something more substantial in order to get this proposal passed. Let
>> me explain.
>>
>> Language design is not like politics. It’s not like mathematics
>> either, but I don’t think this situation is at all similar to
>> negotiating a higher minimum wage in exchange for a lower pension,
>> where you can definitely argue about exactly how much lower/higher
>> you’re willing to go. So I don’t think it’s right to propose making
>> the feature a little bit uglier just to get it accepted.
>>
>> Frankly, 90% of the issue is about what among the authors we’ve dubbed
>> the “load/store” problem (although Tobias never tires to explain that
>> the “load” part is really “load-and-compare”). There’s a considerable
>> section devoted to this topic in the PEP, but I’d like to give it
>> another try here.
>>
>> In case you’ve been avoiding python-dev lately, the problem is
>> this. Pattern matching lets you capture values from the subject,
>> similar to sequence unpacking, so that you can write for example
>> ```
>> x = range(4)
>> match x:
>> case (a, b, *rest):
>> print(f"first={a}, second={b}, rest={rest}") # 0, 1, [2, 3]
>> ```
>> Here the `case` line captures the contents of the subject `x` in three
>> variables named `a`, `b` and `rest`. This is easy to understand by
>> pretending that a pattern (i.e., what follows `case`) is like the LHS
>> of an assignment.
>>
>> However, in order to make pattern matching more useful and versatile,
>> the pattern matching syntax also allows using literals instead of
>> capture variables. This is really handy when you want to distinguish
>> different cases based on some value, for example
>> ```
>> match t:
>> case ("rect", real, imag):
>> return complex(real, imag)
>> case ("polar", r, phi):
>> return complex(r * cos(phi), r * sin(phi))
>> ```
>> You might not even notice anything funny here if I didn’t point out
>> that `"rect"` and `"polar"` are literals -- it’s really quite
>> natural for patterns to support this once you think about it.
>>
>> The problem that everybody’s been concerned about is that Python
>> programmers, like C programmers before them, aren’t too keen to have
>> literals like this all over their code, and would rather give names to
>> the literals, for example
>> ```
>> USE_POLAR = "polar"
>> USE_RECT = "rect"
>> ```
>> Now we would like to be able to replace those literals with the
>> corresponding names throughout our code and have everything work like
>> before:
>> ```
>> match t:
>> case (USE_RECT, real, imag):
>> return complex(real, imag)
>> case (USE_POLAR, r, phi):
>> return complex(r * cos(phi), r * sin(phi))
>> ```
>>
>
> Forgive the intrusion, in case this wasn't already mentioned (I only read
> a fraction of emails on this), we could say that name enclosed in
> parenthesis would mean loading a constant, instead of storing in a variable:
>
> match t:
> case ((USE_RECT), real, imag): # matches the constant USE_RECT
> literal value
> return complex(real, imag)
> case (USE_POLAR, r, phi): # the USE_POLAR portion matches
> anything and stores in a USE_POLAR variable
> return complex(r * cos(phi), r * sin(phi))
>
> Advantages: in Python (and most programming languages), (x) is the same
> thing as x. So, no new syntax, or weird symbols, need to be introduced.
>
> But the parser can distinguish (I hope), and guide the match statement
> generation to the appropriate behaviour.
>
> Yes, it's more typing, but hopefully the case is uncommon enough that the
> extra typing is not a lot of burden.
>
> Yes, it's easy to type USE_RECT when you really meant (USE_RECT).
> Hopefully linters can catch this case and warn you.
>
> OK, that's it, I just thought it was worth throwing yet another idea into
> the pot :-)
>
> --
> Gustavo J. A. M. Carneiro
> Gambit Research
> "The universe is always one step beyond logic." -- Frank Herbert
>


--
Gustavo J. A. M. Carneiro
Gambit Research
"The universe is always one step beyond logic." -- Frank Herbert
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
Ethan Furman wrote:
> Why is this no longer an issue? My apologies if I missed it in the PEP.

This problem was an artifact of the default `object.__match__` implementation, which allowed one positional argument by default when `__match_args__` was missing or `None`. Since we've removed `__match__` from the proposal (and therefore the default `__match__` implementation from `object`), this issue no longer exists.

(Note that most common built-in types like `int` and `tuple` will still work this way, but this behavior is not inherited by *all* objects anymore).
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/NFP22VPMLZ4EERYU6KEB2KO7KQQ7ETA5/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 08/07/2020 19:08, Antoine Pitrou wrote:
> On Wed, 8 Jul 2020 18:38:12 +0100
> Rhodri James <rhodri@kynesim.co.uk> wrote:
>> On 08/07/2020 16:02, Guido van Rossum wrote:
>>> Today I’m happy (and a little trepidatious) to announce the next
>>> version of PEP 622, Pattern Matching.
>>
>> Thank you very much to everyone who has been working on this, it is much
>> appreciated. I have one suggestion for the text: could the section on
>> Capture Patterns emphasise that only simple (i.e not dotted) names are
>> capture patterns? The simplified grammar is (fairly) clear and the
>> later section on Constant Value Patterns should make it obvious, but
>> somehow when reading version 1 I still managed to miss it. I was quite
>> surprised when it was pointed out that
>>
>> case (point.x, point.y):
>>
>> wasn't going to do what I expected!
>
> Why did you expect? It's not clear to me what it should do at all :-)

I was expecting it to unpack a 2-tuple(/sequence?) into the x and y
attributes of this point object I happened to have in my back pocket
(assuming it matched, of course). It actually matches a 2-tuple against
the values of those attributes (i.e. they are constant value patterns).
It's obvious enough once you have time to read the PEP properly -- I
blame only having so many minutes of reading time in my
compile/download/test cycle!

To use code(ish) examples rather than confusable words, suppose we have:

class Point:
def __init__(self):
self.x = 0
self.y = 0

point = Point()
INCOMING = (1, 2)

match INCOMING:
case (point.x, point.y):
print("Point @", point.x, point.y)
case _:
print("Default")

I expected printout of:

Point @ 1 2

but I would actually get

Default

If on the other hand INCOMING was (0, 0), I would get

Point @ 0 0

because the first case is in fact the equivalent of

case (0, 0):

Obviously this is a pointless example (pun intended) because you would
use a class pattern if you really wanted to do something like what I
first thought of.

--
Rhodri James *-* Kynesim Ltd
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/5IWR4AM7YFXG2CK4IHTAJB45FTBXH3AK/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 08/07/2020 19:27, Gustavo Carneiro wrote:
> Forgive the intrusion, in case this wasn't already mentioned (I only read a
> fraction of emails on this), we could say that name enclosed in parenthesis
> would mean loading a constant, instead of storing in a variable:

It's discussed as the third bullet point under "Alternatives for
constant value pattern": https://www.python.org/dev/peps/pep-0622/#id74
Basically it looks odd and we may need parentheses to manage grouping in
patterns.

--
Rhodri James *-* Kynesim Ltd
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/MMIHVMJEUQASMBTPUKIWZZXINRG43E5V/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On Wed, 8 Jul 2020 20:08:34 +0200
Antoine Pitrou <solipsis@pitrou.net> wrote:
> On Wed, 8 Jul 2020 18:38:12 +0100
> Rhodri James <rhodri@kynesim.co.uk> wrote:
> > On 08/07/2020 16:02, Guido van Rossum wrote:
> > > Today I’m happy (and a little trepidatious) to announce the next
> > > version of PEP 622, Pattern Matching.
> >
> > Thank you very much to everyone who has been working on this, it is much
> > appreciated. I have one suggestion for the text: could the section on
> > Capture Patterns emphasise that only simple (i.e not dotted) names are
> > capture patterns? The simplified grammar is (fairly) clear and the
> > later section on Constant Value Patterns should make it obvious, but
> > somehow when reading version 1 I still managed to miss it. I was quite
> > surprised when it was pointed out that
> >
> > case (point.x, point.y):
> >
> > wasn't going to do what I expected!
>
> Why did you expect? It's not clear to me what it should do at all :-)

Sorry: /what/ did you expect?

Regards

Antoine.

_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/VSO5QIGO33GY6KFEHA5RVI2PUNBF3OI3/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 07/08/2020 10:44 AM, Ethan Furman wrote:

> So namespaced variables only...  is there a recommendation on handling global() and local() type variables?

Okay, some off-list discussion clarified that for me:

- easiest way is to use a guard


> ```
> def foo(x, spam):
> match x:
> case Point(p, q, context=c) if c == spam:
> # Match
> ```

If there's a bunch, then SimpleNamespace can be used:

> ```
> def foo(x, spam):
> L = SimpleNamespace(**locals)
> match x:
> case Point(p, q, context=L.spam):
> # Match
> ```

So there we have it -- two ways to do it! ;-)

--
~Ethan~
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/RFFG4UDD4BGSYPS4YCFQ7ADDV773LPBR/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 9/07/20 3:30 am, Luciano Ramalho wrote:
> I strongly favor the option of aligning the `else` clause with
> `match`, because `else` is a special clause therefore it should look
> special.

But on the other hand, it's semantically equivalent to 'case _:',
so it's not all that special.

--
Greg
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/GY73UNHZZGQDAA6FSPZXPKKTUXHPGSP6/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 08/07/2020 16:02, Guido van Rossum wrote:
>
> ```
>     USE_POLAR = "polar"
>     USE_RECT = "rect"
> ```
> Now we would like to be able to replace those literals with the
> corresponding names throughout our code and have everything work like
> before:
> ```
>     match t:
>         case (USE_RECT, real, imag):
>             return complex(real, imag)
>         case (USE_POLAR, r, phi):
>             return complex(r * cos(phi), r * sin(phi))
> ```
> Alas, the compiler doesn’t know that we want `USE_RECT` to be a
> constant value to be matched while we intend `real` and `imag` to be
> variables to be given the corresponding values captured from the
> subject. So various clever ways have been proposed to distinguish the
> two cases.
I apologise for posting a second message re the same idea, but I can't
contain my enthusiasm for it:-)
and I want to make sure it's not overlooked:
*Use '==' to mark* (when necessary) *load-and-compare items*:
    match t:
        case (==USE_RECT, real, imag):
            return complex(real, imag)
        case (==USE_POLAR, r, phi):
            return complex(r * cos(phi), r * sin(phi))

allowing incidentally a possible future extension to other relational
operators:
    case Point(x, >YMAX):
    case >= 42:

>
> If this really is a deal-breaker after all other issues have been
> settled, we could go back to considering some special markup for
> load-and-compare of simple names (even though we expect this case to
> be very rare). But there’s no pressing need to decide to do this now
> -- we can always add new markup for this purpose in a future version,
> as long as we continue to support dotted names without markup,
> since that *is* a commonly needed case.
>
Except that if this idea were taken to its logical conclusion,
    mod.var        would be a capture variable (contrary to the PEP)
    ==mod.var    would be a load-and-compare value
Which may be controversial, but seems to have more overall consistency.
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 08/07/2020 12:30, Rhodri James wrote:
> Any name used as a pattern is a catch-all.  The only difference
> between "case dummy:" and "case _:" is that "_" doesn't bind to the
> thing being matched, but "dummy" does bind to it.

I meant catch-all as in "case _:" (or "else:"). I apologise for the lack
of clarity.

On 08/07/2020 17:02, Guido van Rossum wrote:

> There’s one other issue where in the end we could be convinced to
> compromise: whether to add an `else` clause in addition to `case
> _`. In fact, we probably would already have added it, except for one
> detail: it’s unclear whether the `else` should be aligned with `case`
> or `match`. If we are to add this we would have to ask the Steering
> Council to decide for us, as the authors deadlocked on this question.
Thanks for the write-up. What were the arguments in support of aligning
else with case? I expect it has to be with aesthetics, but for what
concerns semantics, it seems to me that "match...else", interpreted as
"no match was found" would make the most sense; aligning it with case
would look like the else has to do with whatever case was last.
Unless both match and all cases are on the same indentation level. Here
an example:

match:
    variable
case "some constant":
    # ...
case x if x == guard_clause:
    # ...
else:
    # ...

I know at least Elm indents the match variable on a separate line.

On 08/07/2020 19:44, Tim Peters wrote:
> One microscopic point:
>
> [Guido]
>> ...
>> (if `.x` is unacceptable, it’s unclear why `^x` would be any
>> better),
> As Python's self-appointed spokesperson for the elderly, there's one
> very clear difference: a leading "." is - literally - one microscopic
> point, all but invisible. A leading caret is far easier to see, on a
> variety of devices and using a variety of fonts. Indeed, I missed the
> leading dot in ".x" in your email the first two times I read that
> sentence.
>
> But a caret is harder to type. So here's an off-the-wall idea: use
> an ellipsis. If you're still using a maximal-munch lexer, ellipsis
> followed by an identifier is currently a syntax error. "...x" is far
> easier to see than ".x', easier to type than "^x", and retains the
> mnemonic connection that "something is a named load pattern if and
> only if it has dots".

+1 on a simple dot being hard to see.

Alternative idea: if we really ought to have a mark for references¹, why
not use the & symbol, which already signifies something like "reference"
in C(++) and Rust?

¹: I know marking "store" instead of "load" has been suggested before;
I'm still on the fence on which I prefer but I would even accept marking
both (with = and == respectively, for example).
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/YH3SXITYAAPEVD4RKH6OPSWWJZEHGGC3/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On Wed, Jul 8, 2020 at 7:23 PM Rob Cliffe <rob.cliffe@btinternet.com> wrote:

> *Use '==' to mark* (when necessary) *load-and-compare items*:
> match t:
> case (==USE_RECT, real, imag):
> return complex(real, imag)
> case (==USE_POLAR, r, phi):
> return complex(r * cos(phi), r * sin(phi))
>
> allowing incidentally a possible future extension to other relational
> operators:
> case Point(x, >YMAX):
> case >= 42:
>

The problem with this is that value patterns don't just appear at the top
level.
Consider this example from the PEP's deferred ideas section:

case BinaryOp(left=Number(value=x), op=op, right=Number(value=y)):

Using your notation, this would become:

case BinaryOp(left=Number(value===x), op===op,
right=Number(value===y)):

The tokenizer, which is eager, would interpret '===' as '==' followed by
'=' and it would treat this as a syntax error. Also, it looks a lot like a
JavaScript equivalency (?) operator.

A single '=' prefix suffers from pretty much the same thing -- Python's
tokenizer as well as the tokenizer in most people's heads would read
'x==op' as containing '=='.

Please drop it.

--
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*
<http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On 09/07/2020 01:27, Ethan Furman wrote:
> On 07/08/2020 10:44 AM, Ethan Furman wrote:
>
>> So namespaced variables only...  is there a recommendation on
>> handling global() and local() type variables?
>
> Okay, some off-list discussion clarified that for me:
>
> - easiest way is to use a guard
>
>
>> ```
>>     def foo(x, spam):
>>         match x:
>>             case Point(p, q, context=c) if c == spam:
>>                 # Match
>> ```
I like this one. Doesn't it also solve the issue of store vs. load?
Everything is stored but the guard clause can look-up.
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
Much of the discussion seems to focus on how to distinguish between a variable as a provider of a value and a variable as receiver of a matched value.

In normal Python syntax a variable in an expression provides a value, please let’s keep that unchanged.

So it seems to me we should explicitly mark a variable to receive a matched value.
I have seen ‘?’ suggested as a prefix to do this, ‘\’ would also do fine.

This would solve the single variable issue, too:
case foo:
matches the value of ‘foo’, while
case \foo:
matches anything and stores it in ‘foo’.

This would also mean
case Point(x=\x, y=\y):
should be used to obtain x and y from the Point instance.
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/3MC2ZKDVRSDYRBZSYSFDR4M6GKQXITO2/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
> On 9 Jul 2020, at 17:49, Federico Salerno <salernof11@gmail.com> wrote:
>
> On 09/07/2020 01:27, Ethan Furman wrote:
>> On 07/08/2020 10:44 AM, Ethan Furman wrote:
>>
>>> So namespaced variables only... is there a recommendation on handling global() and local() type variables?
>>
>> Okay, some off-list discussion clarified that for me:
>>
>> - easiest way is to use a guard
>>
>>
>>> ```
>>> def foo(x, spam):
>>> match x:
>>> case Point(p, q, context=c) if c == spam:
>>> # Match
>>> ```
> I like this one. Doesn't it also solve the issue of store vs. load? Everything is stored but the guard clause can look-up.

I have to say I find this to be the most satisfactory solution – everything else (dot previously, no dot now, any other single character hypotheticaly) provides users with IMO too big of a footgun to shoot themselves with.

Jakub
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/NXHOLMMS23GLN5QR6BQOHT6ABTI4IOIW/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
One thing I don't understand about the PEP:

    case [x,y]:

IIUC matches any 2-element sequence.
How would you match specifically a 2-item list (say)?
Would it be

    case list([x,y]):

I would appreciate it if some kind person could enlighten me.
TIA
Rob Cliffe
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/NJLVOPNAZIDOCYYGJ2RJKK23ZK5FCLXT/
Code of Conduct: http://python.org/psf/codeofconduct/
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
Yes, you’ve got that exactly right! I think the pep has an example for
tuple((x, y)).

On Thu, Jul 9, 2020 at 13:08 Rob Cliffe via Python-Dev <
python-dev@python.org> wrote:

> One thing I don't understand about the PEP:
>
> case [x,y]:
>
> IIUC matches any 2-element sequence.
> How would you match specifically a 2-item list (say)?
> Would it be
>
> case list([x,y]):
>
> I would appreciate it if some kind person could enlighten me.
> TIA
> Rob Cliffe
> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-leave@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/NJLVOPNAZIDOCYYGJ2RJKK23ZK5FCLXT/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
--
--Guido (mobile)
Re: PEP 622 version 2 (Structural Pattern Matching) [ In reply to ]
On Thu, Jul 9, 2020 at 1:42 PM Eric Nieuwland <eric.nieuwland@gmail.com>
wrote:

> Much of the discussion seems to focus on how to distinguish between a
> variable as a provider of a value and a variable as receiver of a matched
> value.
>
> In normal Python syntax a variable in an expression provides a value,
> please let’s keep that unchanged.
>

For patterns, these are no different than parameters for a function (either
a lambda expression or with `def`); or target assignments in unpacking
assignments. So just like I wouldn't wonder where `a` and `b` materialized
in the parameters for the function definition below

def sum2(a, b):
return a + b

I think it will be straightforward to understand this in the context of a
`case` using a capture pattern:

match x:
case (a, b):
return a + b
...

(This commonality between cases and function definitions is further used in
Scala for example, but I don't see that approach for defining an idea of
partial functions -- not like functools.partial functions! -- as being that
useful in Python.)


> So it seems to me we should explicitly mark a variable to receive a
> matched value.
> I have seen ‘?’ suggested as a prefix to do this, ‘\’ would also do fine.
>
> This would solve the single variable issue, too:
> case foo:
> matches the value of ‘foo’, while
> case \foo:
> matches anything and stores it in ‘foo’.
>
>
Explicit namespacing (if a constant) or using a guard (if a variable) seems
to be the right solution, as Ethan demonstrated earlier. No need for . or ^
or \ or ... to disambiguate. Also it seems to me that structural pattern
matching will build on two common usages of namespaces for constants:

1. Constants used from other modules are almost always used in the module
namespace. Eg, socket.AF_UNIX or signal.SIGTERM.
2. New code often tends to use constants defined within an Enum namespace.
Hopefully we will see more of this convention in usage.

(Very much an aside: Interestingly with the socket module we see both used
- it defines its constants with IntEnum and exports them traditionally. The
namespace specifics it uses with IntEnum._convert_ to make this happen --
strictly speaking EnumMeta._convert, not documented, and a bit hard to
follow -- might be possibly debatable, but it works out quite well in
practice in providing backwards compatibility while continuing to work with
a C source of these constants.)


> This would also mean
> case Point(x=\x, y=\y):
> should be used to obtain x and y from the Point instance.
> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-leave@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/3MC2ZKDVRSDYRBZSYSFDR4M6GKQXITO2/
> Code of Conduct: http://python.org/psf/codeofconduct/
>

1 2 3 4 5 6 7  View All