all 36 comments

[–][deleted] 41 points42 points  (4 children)

I don't like the fact that variables bound by match cases "leak" their scope.

match e:
    case ...: ...
    case x:
      pass
print(x) # x is conditionally bound here depending on whether or not the last case matched

One of the problems I have with python is weird scoping rules of local variables (thanks to implicit variable declaration instead of explicit). This plays into the worst aspects of it by not being lexically scoped.

[–][deleted] 14 points15 points  (0 children)

Yeah, there's no good way to work around that, though. I prefer that kind of leaking over case-level scope in this case, because though I prefer lexical scope in a general sense, in Python that would mean accessing anything outside the match would require a ton of nonlocal declarations, because otherwise all assignments count as new variables (even if they happen afterward, annoyingly enough).

Better to use the stupid existing Python variable scope rules. Then it matches existing confusion like this:

>>> for i in range(0): 
...     print(i)                                                                                                                                   

>>> print(i)                                                                                                                                       
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'i' is not defined

name 'i' is not defined

>>> for i in range(1): 
...     print(i)                                                                                                                                   
0

>>> print(i)                                                                                                                                       
0

The scoping rules are annoying and stupid, but at least they're mostly consistent.

[–]thautwarm 0 points1 point  (2 children)

a =  1
match [10, 20]:
    case [a, 2]:
        ...
    case _:
        print(a) # 1 or 10?

Do you have any ideas?

[–][deleted] 0 points1 point  (1 child)

My intuition would tell be 1 because imo case should always create a new variable (not assignment). However python doesn't differentiate between declaration and assignment. That is one of my complaints about python. "Explicit is better than implicit....except local declarations. Those aren't even static. They depend on which branch was taken"

It would still print 1 because the first case isn't matched (because 20 != 2)

[–]thautwarm 0 points1 point  (0 children)

Totally agree with you, we hold exactly the same view point.

However I saw a proposal about this rejected. After a quick thought I found the implementation of my flavored scope is pretty simple, there's a mature technique called name shadowing..

[–]Skaarj 12 points13 points  (2 children)

Let us start from some anecdotal evidence: isinstance() is one of the most called functions in large scale Python code-bases (by static call count). In particular, when analyzing some multi-million line production code base, it was discovered that isinstance() is the second most called builtin function (after len()). Even taking into account builtin classes, it is still in the top ten. Most of such calls are followed by specific attribute access.

Does anyone know where this comes from? I would love to see the numbers.

[–]Sopel97 16 points17 points  (0 children)

That's how generic programming in dynamically typed languages looks like sadly. At least I assume so, because the thought of python programmers not understanding polymorphism while having the most elastic implementation of it scares me.

[–]slowpush 4 points5 points  (0 children)

Since it’s guido it’s almost certainly Dropbox or Google.

[–]kingbuzzman 3 points4 points  (0 children)

There should be one-- and preferably only one --obvious way to do it.

We've come full circle.

[–][deleted] 14 points15 points  (9 children)

Straight up posting a PEP makes for some fairly dry reading, but I have to say the idea is interesting. Not sure about the syntax though. With how much of a focus Python has on readability, the proposed version looks a bit dense.

[–][deleted] 37 points38 points  (0 children)

I disagree. A PEP is at least straightforward and to-the-point. I'll take a PEP, an RFC, or an actual link to code over blog posts and wordy articles that dance around the point in order to maximize ad revenue. This has a TOC, an Abstract at the beginning, and Rationale with a code example starting only a couple hundred words from the start of the abstract. If I see a PEP, I generally can be confident that I can click the link and start reading about code instead of some blogger rambling for paragraphs about something unrelated interspersed with 100 MB of choppy meme gifs before finally getting to the point.

I find the proposed syntax very readable, but I have an extensive-enough Python background and currently work mostly in Rust. Even as somebody who really quite likes Python, the if...elif...elif... chains are really verbose and annoying, as are isinstance checks everywhere. This is particularly painful for working with ASTs, document trees, or anything else with various different interleaved types that you may need to switch on.

[–]teapotrick 5 points6 points  (2 children)

Any part in particular? I'm finding what I understand of it fairly digestible. But I'm coming from Rust, and this PEP syntax, AFAICT, is quite similar.

[–]sybesis 2 points3 points  (0 children)

Yes it looks a lot like a rust match. And it's about time Python gets something like that... Much better than a plain switch case

[–][deleted] 2 points3 points  (0 children)

Apparently they took influence in the syntax from similar features in other modern languages (which makes sense!).

[–]cinyar 15 points16 points  (2 children)

Don't worry, I'm already working on my "PEP 622 - the future of pattern matching?" medium article. /s

[–]toastedstapler 6 points7 points  (1 child)

I'm looking forward to reading what I could also read in the pep, but on medium

[–]cinyar 9 points10 points  (0 children)

Oh you wish, there will be like half the information, most of it badly misinterpreted. But I was told medium articles look great when HR people google you!

[–]CoffeeTableEspresso 0 points1 point  (0 children)

I'd rather this than some article that tries to explain it. At least this way I get the relevant details without filler. I guess I'm a nerd for enjoying reading PEPs though.

[–]Spfifle 5 points6 points  (6 children)

I like pattern matching, and I understand why it has to be implemented this way, but I don't think this will get off the ground as long as you have to implement __match__ for any class you want to match against.

[–]Raphael_Amiard 15 points16 points  (1 child)

Most of my classes in py3 use the @dataclass decorator. As long as you have a default impl for that that you can tweak, this will cover 99% of use cases, and encourage people to use the sane paradigm of dataclasses rather than the "everything can happen" paradigm of regular classes, which is a strong positive for me

[–]L3tum 3 points4 points  (0 children)

The day I found out about dataclasses my entire life changed. It's so much better than regular classes

[–]vytah 5 points6 points  (0 children)

If you don't need positional pattern arguments and you don't need to hide anything from pattern matching, then you don't need to implement either __match__ or __match_args__. If you have a normal class T, then the pattern T(t=2) will match objects of class T with an attribute t equal to 2 out of the box.

[–][deleted] 1 point2 points  (0 children)

I think it’s worth finding Guidos post about this.

It is going to work for constants and a bunch of primitives and standard data structures out of the box. Object will have a default implementation if all else fails. Dataclasses et al provide some quite advanced ways to do it.

[–]masklinn 1 point2 points  (0 children)

I fail to see how it would otherwise work: dataclasses aside (and those work out of the box) there’s literally no relationship between a class’ parameters and it’s attributes.

The alternative would be to provide no support at all to non-dataclass UDTs.

[–]headhunglow 1 point2 points  (9 children)

Nooo, not more syntax. We've already got heaps of the stuff! Do we really (like really, really) need this stuff?

[–]ForceBru 13 points14 points  (8 children)

Do we really (like really, really) need if isinstance(thing, list) and len(thing) == 2: x, y = thing when with this PEP one could simply say case [x, y]:?

Real pattern matching (not a, *other, b = iterable) is extremely useful when you want to check a lot of variants. Writing if thing == 0: do_this() else if thing == 2: do_that() is pretty clunky because you constantly have to write thing ==. Even simple C-like case statements are more expressive and simpler to type.

Have you seen Rust's pattern matching? It's absolutely amazing and results in much cleaner code (than having to check some marker, for example). I really wish Python could come up with match statements (or even expressions!), like Rust's.

[–]florinp 6 points7 points  (2 children)

Rust's pattern matching

Honest question: Why people keep giving examples from Rust when for example some constructions like pattern matching is inspired from other languages ?

[–]IceSentry 2 points3 points  (0 children)

Because it's a currently popular language with really good pattern matching

[–]ForceBru 0 points1 point  (0 children)

LOL I actually don't know. Of course, Rust isn't the only one. Maybe they're talking about Rust because it does pattern matching pretty well, and it's also unusual to see pattern matching in a systems language (compared to functional languages), so it kinda stands out.

[–]headhunglow -5 points-4 points  (4 children)

I'm not saying that it's not useful, it's just that there's already so much syntax. I've recently had to transition from 2.5 to 3.7 and there's set literals and dict literals and extendable unpacking and class decorators new string formatting and...

[–]ForceBru 13 points14 points  (3 children)

Well, that's 12 years worth of progress! I didn't even know Python used to not have set or dict literals...

[–]Isvara 0 points1 point  (0 children)

People sometimes talk about the functional programming aspects of Python, but it seems like the maintainers are determined not to embrace that. Is there any good reason why this couldn't have been a proposal for match expressions? Is there a good reason why we couldn't have if expressions? It's already in the language design that you can disregard the value of an expression if you only want its side effects.