Smuggery: Python 3.10 has match! gasp!

I've been looking into Python a bit lately because a lot of my friends use it. I was delighted to find that Python's match statement is quite similar to Racket's match statement. I use match a lot, so having it carry over was good news.

Then, out of curiosity, I checked when the feature was added to both languages.

Python: v3.10, released October 2021
Racket: v5.0, released June 2010 (might have been earlier but 5.0 is the earliest version listed on Racket: All Versions)

Python is adorable!

1 Like

Actually, match has existed since at least 2005, according to https://github.com/racket/racket/blob/017d151d5929b49f01d83f9e41995b035cad23de/collects/mzlib/match.ss which was the oldest I could quickly find online. If the SVN history goes back further, I might be able to find older with the Git CLI. Anyway, I think it might have been "PLT Scheme" then, too, since 5.0 was the rename to Racket?

Oh, and ML had it first :slight_smile:

2 Likes

You can find the older version control history here: GitHub - racket/old-plt: The very old history of Racket

Racket has had pattern matching almost since the beginning in 1995. There's a history in my paper here: [1106.2578] Extensible Pattern Matching in an Extensible Language

3 Likes

I am completely unsurprised that it's been there since before v5. :grin: That was simply the earliest I could find in 20 seconds of searching.

Racket’s match is derived from Scheme 84’s, which I started in 1984.

3 Likes

Please no smuggery. :wink:

Here's a bit more context on why it's less attractive to have match in Python.

A match statement maybe isn't a good fit for Python, at least not as much as match in Racket.

Racket and other FP languages usually have match expressions, whereas Python has a match statement (which is understandable since Python is primarily an imperative language). Also, different from Racket, Python in general uses a single scope for everything defined in a function or method. Therefore, a match statement in Python isn't a good fit for the language, different from the match expression in Racket.

Here's how it plays out. First, let's see a Racket example. (I'm not going into details, I only want to show how Python differs.)

#lang racket

(define (func)
  (define a 1)
  (define b '(2 3))
  (match b
    [(list a b)
     (displayln "matched!")])
  ; 1
  (printf "a = ~a~n" a)
  ; '(2 3)
  (printf "b = ~a~n" b))

(func)

The match expression (used here like a statement) defines it's own scope. The values a and b in the match expression don't affect anything outside the match expression.

On the other hand, this is how it looks in Python:

def main():
    a = 1
    b = (2, 3)
    match b:
        case (a, b):
            print("matched!")
    # 2 (was 1)
    print("a =", a)
    # 3 (was (2, 3))
    print("b =", b)

main()

Here, the case assigns new values (2 and 3, respectively) to the variables a and b - and this change is visible outside the match statement!

Python has become a complex language, and not everyone wants it to become even more complex.

Despite the superficial appearance, Python has become rather complex over the years. For example, look at the currently supported special method names. I'm not going into details, but many people (me included) think that Python has accumulated already too much complexity, so it wouldn't be advisable to add even more, for example in form of the match statement with its own "sub-language" rules. Larry Hastings explains it well. Here's some more discussion along these lines.

Note that this is a different line of thought from whether someone personally likes the match concept. For example, I do like match in Racket and Rust, but I'm still skeptical whether it should have been added to Python.

3 Likes

:notes: It's my party thread and I'll cry smug if I want to, smug if I want to, oooh... :notes: (Sorry, couldn't resist.)

Yeah, after reading through the Python documentation and playing around with it a bit I see what you mean about complexity. On the other hand, it's all pretty familiar. It's basically "Let's take Perl and make whitespace significant, get rid of the punctuation and associated semantic value, context awareness, AUTOLOAD dispatch, and default value return, then make OOP class data public by default, then jam in a bunch of stuff from Lisp and call it a day."

.

Being more serious and less smug: I've known for a long time that Python was impressive, I've simply never gotten around to learning it. Now that I'm looking at it, I see that it has earned its enormous market share. It's easy to get started with and it's got a lot of depth, plus it has some excellent libraries and frameworks.

2 Likes

I agree! :slight_smile:

Python certainly has its downsides, but if you avoid the more obscure stuff :wink: , it's quite straightforward and expressive. There used to be the expression for Python "pseudo code that actually runs." (I think it still holds, but I think the expression is nowadays used less than it used to be.)

And could I also add:

  1. Python does not (at the moment) have a way of doing list-rest (If you try to capture more than one "multiple" terms using more than one * you get a "multiple starred names in sequence pattern" syntax error)

  2. Python does not (officially) have tail calls. So although you can match, you still have to write additional code to handle recursion when required. With Racket's match you can recursively match->evaluate and it is all viewed as one (maybe long) function invocation. The result simply flows.

    • There is tco which is not too bad but although it reached the point of a PEP, it did not make it through.
2 Likes