Live data from Hacker News

PEP 622 – Structural Pattern Matching

python.org

51–60 of 131 posts

Re: PEP 622 – Structural Pattern Matching

#51
post #12

Can someone explain to me the history behind Python's aversion to switch statements? I get Python is opinionated and I'm not trying to start a language war, it was just never clear to me why the `if ... elif` pattern was the preferred idiom.

I think culturally, because “explicit is better than implicit” (from the Zen of Python). Switch statements have a lot of implicit-ness to them (implicit invocation of equality comparison, to start) and it never seemed quite necessary, given how spare Python syntax is anyway.

I'd say the opposite: switch is explicitly about comparing a single variable against an enumerated set of possibilities, the equivalent if/elif construct has those same semantics only implicitly. The surface area of what switch/case means is very small and compact.

Re: PEP 622 – Structural Pattern Matching

#52
post #3

glad to see this! though it's a shame that the proposed `match/case` is a statement, not an expression: > "We propose the match syntax to be a statement, not an expression. Although in many languages it is an expression, being a statement better suits the general logic of Python syntax." no matching in lambdas unless those get overhauled too :( instead, let's get excited for a whole bunch of this: match x case A: res…

Yeah, came here to say the same thing. Disappointing to have to write this:

    match shape:
        case Square(l):
            area = l * l
        case Rectangle(l, w):
            area = l * w
        case Circle(r):
            area = (PI * r) ** 2
when I want to just write this:

    area = match shape:
        case Square(l):
            l * l
        case Rectangle(l, w):
            l * w
        case Circle(r):
            (PI * r) ** 2
I'm almost guaranteed to forget (or mistype) the `area = ` at least once in any match clause of length.

Re: PEP 622 – Structural Pattern Matching

#53
Lately, Elixir has dethroned Python as the language that I get the most joy from using. Pattern matching in one of the big reasons. Great to see that Python core contributors (including Guido!) wants to see this feature in Python as well! Hopefully it will be well integrated and not feel like a tacked on feature.

If you're curious about why this is so useful, and reading the (quite dry) PEP isn't your thing, I would heartily recommend playing with Elixir for a few hours. Pattern matching is a core feature of the language, you won't be able to avoid using it. The language is more Ruby-like than Python-like, but Python programmers should still have an easy time grokking it. When I was getting started I used Exercism [1] to have some simple tasks to solve.

[1] https://exercism.io/tracks/elixir

Re: PEP 622 – Structural Pattern Matching

#54

So it’s actually a smart switch statement. Seems like it doesn’t create instances when you’re doing Node(children=[Leaf(value="("), Node(), Leaf(value=")")]) instead: 1. Node means "is instance of Node". 2. Everything in between () is "has an attribute with value". 3. List means "the attribute should be treated as a tuple of".. etc.. Very confusing, this definitely needs another syntax, because both newcomers and exp…

At the current rates, it seems like it's only going to be another 5 years or so before Python is straight-up a more complicated language than Perl 5. What it lacks in frankly bizarre corner cases it's going to make up for in subtly bizarre corner cases.

I used to feel like I could define __getattr__ or __setattr__ and understand the implications, but that's getting increasingly terrifying.

Re: PEP 622 – Structural Pattern Matching

#55
post #6

Very interesting. This PEP is still in draft state, but I am interested to see how the community will react. For me, I have a few thoughts: 1) This is really close to Erlang/Elixir pattern matching and will make fail-early code much easier to write and easier to reason about. 2) match/case means double indentation, which I see they reasoned about later in the "Rejected ideas". Might have a negative impact on readabil…

One difference I noticed from Elixir was this:

> While matching against each case clause, a name may be bound at most once, having two name patterns with coinciding names is an error.

  match data:
    case [x, x]:  # Error!
      ...
Which is a bit of a shame. This comes in handy in Elixir to say "the same value must appear at these places in the collection". I.e. for a Python tuple pattern `(x, y, x)`, `(3, 4, 5)` would not match but `(3, 4, 3)` would.

Overall, though, I think this will be a great addition to Python. Pattern matching is generally a huge boost for expressiveness and readability, in my opinion.

Re: PEP 622 – Structural Pattern Matching

#56

This is very exciting! One subtle thing which I noticed is the distinction between class patterns and name patterns (bindings). In particular, it is possibly confusing that the code `case Point:` matches anything and binds it to the value Point, whereas `case Point():` checks if the thing is an instance of Point and doesn’t bind anything.

Yeah, that seems like it's going to cause trouble, because you can make a mistake without noticing. If you write `case Point:` when you mean `case Point():` you won't get an exception or a missing name, it'll just look like it thinks all objects are Points.

Linters could help. You're shadowing `Point`, and because `case Point:` matches any value, if there's another case after that then something is wrong. But you can't always rely on linters.

Re: PEP 622 – Structural Pattern Matching

#57

So it’s actually a smart switch statement. Seems like it doesn’t create instances when you’re doing Node(children=[Leaf(value="("), Node(), Leaf(value=")")]) instead: 1. Node means "is instance of Node". 2. Everything in between () is "has an attribute with value". 3. List means "the attribute should be treated as a tuple of".. etc.. Very confusing, this definitely needs another syntax, because both newcomers and exp…

> Very confusing, this definitely needs another syntax

The entire point of structural pattern matching is that structuring and destructuring look the same.

> This syntax goes against Zen: It’s implicit -- when using match case expressions don't mean what they regularly mean.

There's nothing implicit to it. The match/case tells you that you're in a pattern-matching context.

> I’m a big believer in this feature, it just needs some other syntax. Using {} instead of () makes it a lot better. Now no way to confuse it with simple equality.

Makes it even better by… looking like set literals and losing the clear relationship between construction and deconstruction?

Re: PEP 622 – Structural Pattern Matching

#58

Earlier quoted context omitted.

I prefer the PEP syntax: it looks like the instanciation of the object I'm trying to match, so it makes sense to me.

That's their entire point: you're _not_ instantiating the object you're trying to match.

Pattern matching traditionally resembles instantiation except potentially with wildcards, because the “pattern” in “pattern matching” is a object representation template in the same representation used elsewhere in the language.

Using a different syntax for pattern matching loses the main point of pattern matching.

Re: PEP 622 – Structural Pattern Matching

#59

If you want it today, Pampy does most of it: https://github.com/santinic/pampy Even match on Point(x, y, _)

How did they implement Point(x, y, _) matching? PEP proposes a special protocol [1] based on __match__ classmethod. Do they do something similar?

[1] https://www.python.org/dev/peps/pep-0622/#runtime

Re: PEP 622 – Structural Pattern Matching

#60
post #9
post #8

> case Node(children=[LParen(), RParen()]): Is this will create a second Node instance and compare it to node? If so, is it not less efficient performance wise than it's "counterpart" isinstance() + properties comparison? If this method is less efficient, it could be confusing, specially for newcomer. Am I missing something.

It reads like a Node instance construction, but it's actually syntactic sugar for: isinstance(node, Node) and node.children == [LParen(), RParen()]

It's not quite syntactic sugar, but you're right that (probably) no new object would be created. Based on the "The __match__() Protocol" section [0] of the Pep, matching will call into `Node`'s `__match__` method with `node` as the arg. If Node doesn't have any custom logic here, it'll use the default __match__ implementation [1], which checks `isinstance(node, Node)` like you said, then returns `node` for the python interpreter to check that `node.children` a) is a sequence, b) has two elements, c) has its first element matching `LParen`, using `LParen`'s `__match__` method, and d) has its second element matching `RParen`, using `RParen`'s `__match__` method. If none of these `__match__` methods are overriden, then it does basically function as the parent poster said (though I think it would work even if node.children were some other sequence type (e.g. tuple) containing `LParen()`, `RParen()`).

[0] https://www.python.org/dev/peps/pep-0622/#the-match-protocol [1] https://www.python.org/dev/peps/pep-0622/#default-object-mat...

Post reply on HN