Gauging sentiment on pattern matching

The SC is trying to see whether there is clear consensus on pattern matching in general and PEP 634 specifically. Please vote below to express your current feeling on this topic.

To be clear, this is not a binding vote, but instead to see if any consensus exists among the core team. This poll will close on Monday, Nov 23.

  • Accept PEP 634 as-is
  • Accept PEP 634 + 640
  • Accept PEP 634 + 642
  • I want pattern matching, but not as defined in those PEPs
  • I don’t want pattern matching

0 voters

9 Likes

I kept up with the original pattern matching PEP for a while, but the discussion has splintered so much since then that I’ve had a really hard time keeping up with the current state of affairs.

Maybe it would help give better results or more voter turnout if someone who has been could prepare a very short TL;DR for the salient features of each of these things? (Or maybe not — maybe it would just introduce a bunch of noise from people going with their gut feelings rather than looking at the careful reasoning in the PEP and the back-and-forth discussions).

Sorry for the non-answer here.

5 Likes

I want pattern matching but haven’t been able to spend time reading recent PEPs (let alone infinite emails).

10 Likes

You sort of have that:

So PEP 636 might cover what you’re after.

1 Like

I was more hoping for something like “here is the list of stuff that people found contentious, and here’s how PEP 634, PEP 640 and PEP 642 handle it differently (if at all).”

1 Like

I think the variety and volume is too big to probably get a good summary of it. Honestly, I bet the Rationale section of PEP 635 covers the topics of what typically came up.

3 Likes

I was more hoping for something like “here is the list of stuff that people found contentious, and here’s how PEP 634, PEP 640 and PEP 642 handle it differently (if at all).”

In short:

  • PEP 634 uses _ and *_ for non-binding wildcards. PEP 640 proposes using ? and *? instead, and also allows them to be used in most assignments throughout the language.

  • PEP 642 differs in many ways, and it appears these rules are still in flux to some degree. Its Abstract has a pretty good listing of differences with PEP 634.

6 Likes

Perhaps the most important concern that’s not represented in an additional PEP yet is whether capture variables should be marked with some sigil. If you want this you should probably choose “I want pattern matching, but not as defined in those PEPs”. (But don’t vote that way until you’ve read the section in PEP 635 about this.)

5 Likes
  1. On a personal basis, I feel no strong need for pattern matching and I don’t really care about it. My life won’t be made significantly easier with it.
  2. From a language design POV, I feel pattern matching is one more step that makes Python less approachable for casual users, while it will bring little gain even for expert users.
  3. I would strongly support a long-term moratorium on language additions.
5 Likes

I want pattern matching and in my opinion PEP 634 is good as is.

Few thoughts:

  • Before voting I’d recommend people to look at https://www.python.org/dev/peps/pep-0636/.

  • Pattern matching is something that I briefly used in erlang and thoroughly enjoyed. I think it has a great potential to enhance async/await code (better syntax for implementing events/messaging). I’m excited to see what people will build with it.

  • Pattern matching is extremely useful for compilers and parsers. Something that I have a fair share of experience with, and I’d love Python to be more expressive at that kind of code.

  • I generally find arguments like “Python would become harder to learn” or “Python would become less approachable” to be relatively weak. Beginners don’t use all language features on day 1, and pattern matching as presented is quite intuitive. On the other hand, the new syntax would simplify the spaghetti code that professionals have to work with on a daily basis.

  • Python used to be Guido’s language. And it somehow evolved under his vision to be in the top 5 languages today. PEP 634 is something Guido has been working for a couple of years, at least. He considered multiple cons and pros of the proposal and still thinks this is a great addition, so even if I didn’t want pattern matching, I’d still trust him here.

As for PEP 640: I think that having a special treatment for _ in PEP 634 is acceptable. I’d personally be OK with using ? instead of _ in match..case only, but accepting the entire PEP 640 would mean that we’d see things like for ? in range(3) – something that doesn’t look like Python to me.

15 Likes

I have read through the PEPs 634, 635 and 636 and have a couple of questions:

  • How would the proposal deal with literals which are defined via a function calls or constants ?

    E.g. case CODE_ONE: or case gettext("yes"):

    Esp. when parsing options, it is rather common to use global constants or make the literals depend on some context (eg. locale) rather than putting the literals directly into the code.

    In PEP 636, the “Appendix A” gives a good example: you would not put literal 404 into a case block, but rather use HTTP_NOT_FOUND.

    The way I read the spec, the parser would try to assign the matched value to a variable of the given constant and try to interpret the function call as a type pattern, so effectively making it impossible to use it in this way. Could be wrong, though, or is there some other syntax needed to make this work ?

    Since this kind of literal matching is likely going to be the most common use case of the syntax, I think the PEPs should give more attention to this case, not just mention it in an appendix.

  • PEP 636:

    Under “Matching builtin classes”, why do you have to write str() in {"text": str() as message, "color": str() as c} and not just str (without the parens, giving the type object) ? The str() would evaluate to an empty string (at least intuitively), just like str(""), but the matching really is about the type and not the string value.

  • Experimenting with the syntax:

    Overall, I like the PEP ideas and would very much like to see this in Python. However, given the complexity of the PEPs, there will most likely be lots of small nits in the spec which will only become apparent in actual use of the new syntax.

    Would it be possible to add the syntax only with a from __future__ import pattern_matching_v1 marker to experiment with it for a release or two before making it final ?

    This would give the syntax a chance to mature in practice and at the same make it obvious to readers of the code that the syntax may in fact still change in an upcoming release.

I’ve also had a look at PEP 640 and 642, but don’t really like the syntax these propose. We have to be careful not to create too much line noise in Python.

For now, my vote would go to option 4, but I’ll wait until perhaps someone can educate me on the above questions. TIA :slight_smile:

4 Likes

I voted for PEP 634 as-is.

My other consideration would have been PEP 634 + PEP 640. But, I saw PEP 640 as a standalone proposal in itself.

The use of _ for captured-but-unassigned in PEP 634, used with similar to how I have used “_” in python programs.

I was also a little concerned when I read if “or patterns”, “conditional patterns”, “sub-patterns” support could increase the reading complexity of the python programs, but I am not certain. They could, but it depends on the programmer writing the code, and using these (sub) tools of pattern matching a programmer could write meaningful code too.

1 Like

I voted PEP 634 as-is.

I think pattern matching would be a useful feature. I can easily imagine using it.

Reading PEP 636 (the tutorial) gave me a very good sense of the logic and expected uses of the new feature, and everything felt completely natural in that context. Yes, it’s a tutorial designed to show off the proposed feature, so you’d expect that, but it reassured me that the choices made look sensible and work well in a realistic context (at least in one such).

I don’t like ? as a placeholder, so 640 has no appeal to me, especially because it contradicts the common idiom of using _ in existing Python code.

I wish I understood the point behind 642, but it seems to be a variation without a unified theme to it, and the only impression I really get is that I’d need to put == all over the place when matching. (I know that seems a little unfair, and I’m sorry, but in terms of my “sentiment”, it’s general impressions that count).

1 Like

Thanks for your questions, @malemburg.

How would the proposal deal with literals which are defined via a function calls or constants ?

Simply put: the results of those function calls and the values of those constants would need to be put in a qualified namespace.

>>> class YN:
...     YES = gettext("yes")
...     NO = gettext("no")
... 
>>> match "ja":
...     case YN.YES: ...
...     case YN.NO: ...
...

(You can also use guards for more complicated cases).

Anything “called” basically works as an isinstance check, with the possibility for further destructuring. You’ll get a nice error message if you try to match on something other than a type at run-time:

>>> match "ja":
...     case gettext("yes"): ...
...     case gettext("no"): ...
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: called match pattern must be a type

Similarly, you can have at most one irrefutable pattern. So in practice, trying to use pattern matching as a switch statement on unqualified constants will guide you in the right direction as well (with a SyntaxError at compile-time):

>>> match "ja":
...     case YES: ...
...     case NO: ...
...
  File "<stdin>", line 2
SyntaxError: name capture 'YES' makes remaining patterns unreachable

In PEP 636, the “Appendix A” gives a good example: you would not put literal 404 into a case block, but rather use HTTP_NOT_FOUND.

Or, even better: HTTPStatus.NOT_FOUND from the http module.

Since this kind of literal matching is likely going to be the most common use case of the syntax, I think the PEPs should give more attention to this case, not just mention it in an appendix.

The rejections of PEPs 275 and 3103 were our first hint that this would not be the most common use case of the new syntax. It’s clear that the community needs a different feature - one that can’t be replaced by a dictionary or a trivial if-elif-else ladder. We found, based on a survey of other languages and past discussions, that a destructuring approach (where you match the shape of the object and extract interesting parts from it) was the most promising. We provide the ability to match on equality with a literal or constant as a convenience, not as a core feature.

In fact, the first draft of PEP 622 (superseded by PEP 634) allowed you to use .YES (note the leading dot) to indicate an equality comparison, rather than a capture. It also had the nice effect of having an easy-to-remember rule that “any dotted name in a pattern is a load, not a store”. Unfortunately, this got probably the most pushback of anything in the proposal (too different from the rest of the language, too hard to see, doesn’t make automatic refactoring better, etc.). So we dropped it. If we wanted to add something similar in the future, though, the door is always open to do so. So we can see if this really does cause problems in practice, and respond if necessary.

Under “Matching builtin classes”, why do you have to write str() in {"text": str() as message, "color": str() as c} and not just str (without the parens, giving the type object) ?

Because otherwise it would be ambiguous with capture patterns. The call syntax also allows you to destructure the match subject further by attributes (which, again, is where pattern matching really shines).

It’s sort of the same reason why we can’t just omit the parentheses of zero-argument function/method calls. f would be ambiguous, while f() is not.

Also, note that this is more simply spelled as {"text": str(message), "color": str(c)}.

The str() would evaluate to an empty string (at least intuitively), just like str(""), but the matching really is about the type and not the string value.

Yes, but it’s about more than just the type. While str() is a bit boring, you can zoom out and look to the mapping pattern used in this same example to see why the internal structure can be just as important (if not more important) than the actual type.

Would it be possible to add the syntax only with a from __future__ import pattern_matching_v1 marker to experiment with it for a release or two before making it final ?

This would give the syntax a chance to mature in practice and at the same make it obvious to readers of the code that the syntax may in fact still change in an upcoming release.

The way I see it, that’s what development, alphas, and betas are for. You can even play with it now, if you want to!

4 Likes

However, that gives us – at most and under ideal circumstances – 12 months. IIRC asyncio was a __future__ import for, what, two releases? And those were 18-month releases.

Having said that, I’m fine with going with PEPs 634-6 as I could and would use them right now.

1 Like

For my own understanding, which PEP / __future__ import is this? async and await became hard keywords in 3.7, but I think that was due to compatibility concerns (not a provisional period or anything).

1 Like

Speaking about asyncio, the library did never require from __future__ import ....
Instead, it had a provisional status which means a freedom to add backward incompatible changes if there is no choice.
IIRC typing was provisional as well.

3 Likes

Ah, right – thanks for the clarification!

1 Like

And the result of those two provisional packages was that “provisional” was deemed more trouble than it’s worth, and so we don’t do them anymore (unless you convince the SC to forget that previous decision and do it anyway).

Better to find ways to validate the design before release and commit to it. Python has too many users to get away with blatant API changes these days.

3 Likes

Besides, ‘provisional’ applies to packages (see PEP 411), not to language features.

4 Likes