← Back to context

Comment by Aefiam

2 days ago

case .foo is explicitly mentioned in https://peps.python.org/pep-0622/ :

> While potentially useful, it introduces strange-looking new syntax without making the pattern syntax any more expressive. Indeed, named constants can be made to work with the existing rules by converting them to Enum types, or enclosing them in their own namespace (considered by the authors to be one honking great idea)[...] If needed, the leading-dot rule (or a similar variant) could be added back later with no backward-compatibility issues.

second: you can use case MyObject() as obj: print(obj)

I don't think I've written a match-case yet. Aside from not having a lot of use cases for it personally, I find that it's very strange-feeling syntax. It tries too hard to look right, with the consequence that it's sometimes quite hard to reason about.

> > While potentially useful, it introduces strange-looking new syntax without making the pattern syntax any more expressive. Indeed, named constants can be made to work with the existing rules by converting them to Enum types, or enclosing them in their own namespace (considered by the authors to be one honking great idea)[...]

Yeah, and I don't buy that for a microsecond.

A leading dot is not "strange" syntax: it mirrors relative imports. There's no workaround because it lets you use variables the same way you use them in any other part of the language. Having to distort your program by adding namespaces that exist only to work around an artificial pattern matching limitation is a bug, not a feature.

Also, it takes a lot of chutzpah for this PEP author to call a leading dot strange when his match/case introduces something that looks lexically like constructor invocation but is anything but.

The "as" thing works with primitive too, so why do we need int(m)? Either get rid of the syntax or make it general. Don't hard-code support for half a dozen stdlib types for some reason and make it impossible for user code to do the equivalent.

The Python pattern matching API is full of most stdlib antipatterns:

* It's irregular: matching prohibits things that the shape of the feature would suggest are possible because the PEP authors couldn't personally see a specific use case for those things. (What's the deal with prohibiting multiple _ but allowing as many __ as you want?)

* It privileges stdlib, as I mentioned above. Language features should not grant the standard library powers it doesn't extend to user code.

* The syntax feels bolted on. I get trying to reduce parser complexity and tool breakage by making pattern matching look like object construction, but it isn't, and the false cognate thing confuses every single person who tries to read a Python program. They could have used := or some other new syntax, but didn't, probably because of the need to build "consensus"

* The whole damn thing should have been an expression, like the if/then/else ternary, not a statement useless outside many lexical contexts in which one might want to make a decision. Why is it a statement? Probably because the PEP author didn't _personally_ have a need to pattern match in expression context.

And look: you can justify any of these technical decisions. You can a way to justify anything you might want to do. The end result, however, is a language facility that feels more cumbersome than it should and is applicable to fewer places than one might think.

Here's how to do it right: https://www.gnu.org/software/emacs/manual/html_node/elisp/pc...

> If needed, the leading-dot rule (or a similar variant) could be added back later with no backward-compatibility issues.

So what, after another decade of debate, consensus, and compromise, we'll end up with a .-prefix-rule but one that works only if the character after the dot is a lowercase letter that isn't a vowel.

PEP: "We decided not to do this because inspection of real-life potential use cases showed that in vast majority of cases destructuring is related to an if condition. Also many of those are grouped in a series of exclusive choices."

I find this philosophical stance off-putting. It's a good thing when users find ways to use your tools in ways you didn't imagine.

PEP: In most other languages pattern matching is represented by an expression, not statement. But making it an expression would be inconsistent with other syntactic choices in Python. All decision making logic is expressed almost exclusively in statements, so we decided to not deviate from this.

We've had conditional expressions for a long time.

  • Agreed.

    After starting my new job and coming back to Python after many years I was happy to see that they had added `match` to the language. Then I was immediately disappointed as soon as I started using it as I ran into its weird limitations and quirks.

    Why did they design it so poorly? The language would be better off without it in its current hamstrung form, as it only adds to the already complex syntax of the language.

    > PEP: In most other languages pattern matching is represented by an expression, not statement. But making it an expression would be inconsistent with other syntactic choices in Python. All decision making logic is expressed almost exclusively in statements, so we decided to not deviate from this.

    > We've had conditional expressions for a long time.

    Also, maybe most other languages represent it as an expression because it's the sane thing to do? Python doing its own thing here isn't the win they think it is.

    • The Python core team has kind of run the language off the rails post 3.7 or 3.8 or so. There's been so much crap bolted on to the language for dubious reasons, and often times it comes with whole new sets of weird problems without really making life easier (async was a quintessential example of this in my mind). There's a lot of design choices core to the language itself that make it a poor choice for many tasks, but that never stops anyone from doing it anyways and bolting on lots of chincy "features" along the way.

  • > (What's the deal with prohibiting multiple _ but allowing as many __ as you want?)

    What do you mean "prohibiting multiple _"? As in this pattern:

      match [1,2]:
        case [_, _]: print("A list of two items")
    

    That works fine.

    • > An irrefutable case block is a match-all case block. A match statement may have at most one irrefutable case block, and it must be last.

      There is no reason to have this restriction except that some people as a matter of opinion think unreachable code is bad taste and the language grammar should make bad taste impossible to express. It's often useful to introduce such things as a temporary state during editing. For example,

          def foo(x):
              match x:
                  case _:
                      log.warning("XXX disabled for debugging")
                      return PLACEHOLDER
                  case int():
                      return bar()
                  case str():
                      return qux()
                  case _:
                      return "default"
      

      Why should my temporary match-all be a SyntaxError???? Maybe it's a bug. Maybe my tools should warn me about it. But the language itself shouldn't enforce restrictions rooted in good taste instead of technical necessity.

      I can, however, write this:

          def foo(x):
              match x:
                  case _ if True:
                      log.warning("XXX disabled for debugging")
                      return PLACEHOLDER
                  case int():
                      return bar()
                  case str():
                      return qux()
                  case _:
                      return "default"
      

      Adding a dummy guard is a ridiculous workaround for a problem that shouldn't exist in the first place.

      1 reply →