python’s adding structural pattern matching <https...
# thinking-together
k
python’s adding structural pattern matching https://www.python.org/dev/peps/pep-0622/
🎉 3
😱 1
d
This is one of several "functional programming" features I've been seeing creep into imperative languages over the last few years. I think over time, the really good features of FP and imperative programming wind up crossing the fence until it's almost everywhere.
👍 2
c
I’m not a language geek, but is this similar to PEG that I spotted in Janet recently?
s
Heh, I was just looking at PEP 622. First I was excited, then thought it's very messy and confusing. There's a new 'pattern grammar' which doesn't quite look or work like usual Python. Maybe it will make sense to me at some point.
It's not exactly like PEG. It's a language feature that lets you match objects against a pattern and also extract some matched parts into variables.
So PEGs (and regexes) are matchers for text. This is a built in language syntax to make a matcher for object trees, if that makes any sense.
i
@shalabh I'm curious, what makes you say "doesn't quite look or work like usual Python"?
s
Hehe do we really want to get into PEP 622 here? Mainly it's because the meaning of whatever follows
case
is surprising if you know Python. It's not regular Python, it looks regular but is designed to work as a structure matching (and name binding language). Consider:
case 123:
- matches the value 123. so far so good
abc = 123
case abc:
- matches 123? No, it matches any value because
abc
is a name pattern (will capture any value). What if you really wanted to match the value in the variable
abc
? Well now there's a brand new syntax (which only works inside case):
case .abc
. Then there's the class patterns, which look like calls but actually capture values from an existing structure:
case Point(x, y)
- creates/sets x and y, if the object is a Point. Anyway the PEP is still being worked on so lets see what it looks like eventually.
i
Thanks for going into the details. I don't want to hijack this Slack/thread with programming language minutia, but I'm a PL nerd so I'm always curious to see what new features there are in various languages. I'm writing Scala for my day job and I've also used Haskell, Standard ML and Erlang for personal projects. They all have pattern matching constructs and pretty much all of them expose the same set of features you're talking about, with slight variations of course. From this point of view, at least, this PEP follows "industry standards".
👍 1
e
This type of complex domain specific language with all of its tricks and traps is probably a mistake. For those rare instances when it would be used, you have now added 50 pages in the reference manual to explain all the subtleties. This type of feature is exactly the kind of thing Guido was constantly refusing to add. Now that he has left his position as BDFL, the complexification committee will take care of ruining Python. That's okay, i designed my Beads language as the evolution of Python by simplification, it can only help me.
i
If anything, this feature is in general abused, rather than seldomly used. I quite like it to be honest, but I find it more useful in a language with static typing.
s
Strangely, Guido is one of the PEP authors 😄 Also there is resistance to the PEP from some core Python folk, so lets see where this goes. I like the idea of pattern matching too. Having it from the start in a language means other features were designed with it in mind. In Python it is being added later so it's going to be more complex to make it seem to fit. Consider the
except E as e
syntax - it's already kind of a pattern match using just isinstance. Would we not want matching to work identically in that syntax as well? IIRC you can have destructuring assignment in Erlang and put constants on the left, roughly
"red", a = f()
- this only matches and binds iff f() returns "red" as the first item in a pair. There's no such thing in Python, but you can have only free variables on the left that always get bound. Should that also work now, given the unpacking pattern can use
case ["red", a]
?
👍 1
k
My first impression is much like @shalabh's: this is going to add a lot of complexity to Python, and is likely to become a nightmare for Python teachers. To add a criticism to @shalabh's list:
Point(x, y)
not only looks like a constructor but isn't, it also interprets arguments in a different way from a constructor. Sure, one would expect Python programmers to ensure that a class'
__init__
and
__match__
are semantically compatible, but I bet we will see many classes whose
__init__
allows more variations than
__match__
. And I also bet that people will try to use
class(**args)
as a pattern and expect
class
to be bound to the class object.
👍 1
s
I think a fundamental limitation is also you can only match over a key/value like structure. E.g. you can't match
case Regex('a.*b')
- the inner pattern is not sent to the class, but the class is supposed to return a 'static data field like' structure. So this also will cause problems if you have a few expensive computed properties - are you know supposed to generate and return all of them? What if the caller is only matching one?
k
BTW, this discussion made me think of this paper which basically says that destructuring or pattern-matching objects makes no sense at all. TL;DR: Objects expose only their behavior (via methods), but not their internal data structures.
i
@shalabh for your regex example, it might be possible to do something like:
Copy code
pattern = Regex('a.*b')
match 'aaaab':
    case pattern(matched, capturingGroup1, etc): pass
Regarding your other point, about expensive computations, the PEP says this:
There is no requirement that the attributes on the proxy object be the same type or value as the attributes of the original object; one envisioned use case is for expensive-to-compute properties to be computed lazily on the proxy object via property getters.
Also, your concerns about pattern matching for exceptions and assignments are well founded, but it seems to me that they can add these capabilities later.
@Konrad Hinsen that's a good paper, but pattern matching does not preclude data abstraction, just as using lists and dictionaries does not preclude it. At some point we have to inspect data and patttern matching helps there. Without this, we'd have to ban
return
or
yield
and write our programs in a completely continuation-passing style, which would be quite hard to understand. I feel that once you'll be able to play with it, you'll like it more, unless you've already used pattern matching in some other language and decided it was a bad idea there.
s
@Ionuț G. Stan that seems quite a roundabout way to do regexes, consider if you had multiple cases, you wouldn't be able to write literal regexes inline and have to alias them via new variable names. The PEP also says
__match__
should be a class or static method, so we'll be creating one class per regex.
May main issue though is the seeming arbitrary mixing of 'capture variables' (lvalues) and variables as references. E.g.
a = f()
is clear and
a.b = f()
kinda follows. But
case a
is totally different from
case a.b
- in the latter case it's a reference, the the former case
a
is a name to be bound.
Honestly if all lvalues were tagged or separated, this would be much more acceptable to me. e.g.
case Point as x,y
or
case Point(?x, ?y)
i
I guess you can tag the other case, although it's not enforced:
case .a.b
would work instead of
case a.b
. And I get your point, but on the other hand, the main purpose of pattern matching is to introduce new bindings, so the main use case should introduce as little syntax as possible, I think.
Also, regarding regexes. I haven't seen any language that supports both passing arguments and binding values in a pattern. That would be interesting.
s
I guess you could tag the other case. I also think these are warts: in places where both
x
and
x()
are valid, the
x
part means the same exact thing. But here one is a new name and one is a reference. What if I wanted to match a specific point at a known x,y?
case Point(x, y)
wont work, but I feel it should work, given I can do
case "hello"
and have the value match. Literals and predefined constants get special features here.
k
enlightening thread