Live data from Hacker News

PEP 622 – Structural Pattern Matching

python.org

71–80 of 131 posts

Re: PEP 622 – Structural Pattern Matching

#71
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…

I wonder if this is intentional. FP constructs are increasingly discouraged in Python, taking reduce [1] as an example. Not that this is necessarily a bad thing, per sé -- I think it does simplify the language. But it's an opinionated decision that will discourage FP enthusiasm from finding a home in Python. [1] http://lambda-the-ultimate.org/node/587

> I wonder if this is intentional. FP constructs are increasingly discouraged in Python, taking reduce [1] as an example.

That single comment from Guido 15 years ago, which was largely backtracked on—map and filter remain in the core library and reduce moved to a library in stdlib, lambda remains—is not really an example of something accurately described as “increasingly” now. In fact, given the backtracking, it's arguably decreasingly true from the high point of that post.

Re: PEP 622 – Structural Pattern Matching

#72

Interesting proposal, but I'm cringing at yet another overload for the * symbol. a * b == "a times b" a * * b == "a to the power of b" f(* a) == "call f by flattening the sequence a into args of f" f(* * a) == "call f by flattening the map a into key value args for f" [* a] == "match a sequence with 0 or more elements, call them a" Am I missing something? I know these all occur in different contexts, still the genera…

It's already used that way for unpacking, e.g.

  >>> [x, *other] = range(10)
  >>> x
  0
  >>> other
  [1, 2, 3, 4, 5, 6, 7, 8, 9]
So this instance of the syntax is not that novel. If it's a mistake, it's too late to fix it.

A unary asterisk before a name means the name represents a sequence of comma-separated items. If it's a name you're assigning to (LHS) that means packing the sequence into the name, if it's a name you're reading from (RHS) that means unpacking a sequence out of the name.

Re: PEP 622 – Structural Pattern Matching

#73
post #65

Earlier quoted context omitted.

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 mat…

Which equality will you use if it's not numbers, but something more complicated. What if `(x, y, x)` is matched against some `(a, b, c)` where `a == c`, but not `a is c`? If yes, and you mutate `x` in the body, does it mutate `a` or does it mutate `c`? I think at least making it an error now can leave it open to defining it later.

There's certainly no reason to use reference equality. In fact, I think equality is the wrong question: it should duplicate the match. `case (x, y, x)` should `__match__((a, b, c))` IFF `a.__match__(c)` (Not sure if that's exactly the right syntax for the Python calls, but hopefully the idea is clear.)

(Elixir has a similar operation to "pin" in a match: if you use an existing variable as the pattern, but pin it, the value must match whatever the variable is already bound to.)

> I think at least making it an error now can leave it open to defining it later.

Fair point.

Re: PEP 622 – Structural Pattern Matching

#74

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…

It's worth noting that there's a truly massive amount of precedent in other languages for Python implementing it using the syntax as proposed. Languages that have or are planning to include pattern-matching where the pattern syntax exactly mirrors the expression syntax like this include Rust, Swift, OCaml, Haskell, C++, Ruby, Erlang, and many, many more.

I understand the worry that newcomers might struggle, but I don't think it's going to be the case: newcomers regularly learn the languages listed above without stumbling across that problem. And if Python did choose a syntax like the one you're proposing, it'd also be the odd one out among dozens of mainstream languages including this feature, which I think would be even more confusing!

Re: PEP 622 – Structural Pattern Matching

#75

Interesting proposal, but I'm cringing at yet another overload for the * symbol. a * b == "a times b" a * * b == "a to the power of b" f(* a) == "call f by flattening the sequence a into args of f" f(* * a) == "call f by flattening the map a into key value args for f" [* a] == "match a sequence with 0 or more elements, call them a" Am I missing something? I know these all occur in different contexts, still the genera…

You're missing

    def f(*args, **kwargs):
doing the opposite of

    f(*a)
    f(**a)

Re: PEP 622 – Structural Pattern Matching

#76

Interesting proposal, but I'm cringing at yet another overload for the * symbol. a * b == "a times b" a * * b == "a to the power of b" f(* a) == "call f by flattening the sequence a into args of f" f(* * a) == "call f by flattening the map a into key value args for f" [* a] == "match a sequence with 0 or more elements, call them a" Am I missing something? I know these all occur in different contexts, still the genera…

> Am I missing something?

Yes, the form used in function declaration (the inverse of the form in function calls) which is pretty much exactly the same as the new use, “collect a sequence of things specified individually into a list with the given name”.

Re: PEP 622 – Structural Pattern Matching

#77
post #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.

Pattern matching is implemented as syntaxic sugar on top of if/else in the bytecode.

Behavior doesn't change at all.

Re: PEP 622 – Structural Pattern Matching

#78
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.

Taking this question from the opposite angle, what benefits do switch statements give us over if...elif? Not actually a heavy Python user, but even though most languages I use regularly are more switch/case-heavy, I've never quite grasped why there's two largely interchangeable ways to do the one thing.

> what benefits do switch statements give us over if...elif?

Clarity of intent, much as comprehensions provide over imperative loops (even though switch is still imperative in most langauges). Though whether it's enough benefit to be warranted is another question; I think basic switch is not clearly compelling, though adding even basic smarter matching (like Ruby has long had, for instance) makes it moreso.

Re: PEP 622 – Structural Pattern Matching

#79

Interesting proposal, but I'm cringing at yet another overload for the * symbol. a * b == "a times b" a * * b == "a to the power of b" f(* a) == "call f by flattening the sequence a into args of f" f(* * a) == "call f by flattening the map a into key value args for f" [* a] == "match a sequence with 0 or more elements, call them a" Am I missing something? I know these all occur in different contexts, still the genera…

Yes, that it is pretty much already part of the language like this.

This works:

a, *b = (1, 2, 3, 4)

b will be [2, 3, 4]

Re: PEP 622 – Structural Pattern Matching

#80

Earlier quoted context omitted.

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.

[deleted]
Post reply on HN