"I have a feature that I am sort of jealous of because it's appearing in more and more other languages: pattern matching. And I cannot come up with the right keyword, because all the interesting keywords are already very popular method names for other forms of pattern matching." -Guido van Rossum
I can't find a reference to what parser python uses internally, but if it does at least one token lookahead, wouldn't you be able to disambiguate special syntax from any standard expression since the former allows tokens separated by only a space and the latter doesn't? e.g. afaik `match some_call():` is a syntax error, so you don't need to worry about match being a legal identifier.
I daresay another issue is going to be the syntax -- the naïve way of implementing it nests two blocks: one for the pattern-matched block as a whole, and and another for the actual cases, which means that now you've got a double indent. IIRC this was a reason he gave against implementing case statements way back when.
There is one construct that's almost like a block but doesn't indent code, decorators. It's rich enough to implement multiple dispatch in functions, including pattern-matching on values and not just on types. Unfortunately it won't get you the sort of things you could do with actual blocks, e.g. access to other variables.
I don't think it's a matter of keywords. I'm working with both Elixir and Python on different projects right now.
Pattern matching is very deeply ingrained into Elixir. Two examples to scratch the surface
This is pattern matching in function arguments
def process_file({:ok, {file_name, file_content}}) do
...
:ok
end
def process_file({:error, reason}) do
...
:error
end
def process_file(_), do: error
This is pattern matching in assignment
{:ok, content} = File.read(file_name)
Actually the = character is the pattern matching operator, which accidentally ends up assigning values in some cases: it can't assign to the :ok atom but it can assign to the content variable. If File.read returns {:error, "some error"}, the match will fail and the program will stop. Usually I get a notice from Sentry and a supervisor process will start it again, possibly running into the same problem or not. Sometimes errors are caused by external services that have occasional hiccups.
Some changes are so structural that turn languages into another one and I'm not sure it's worth it. We have so many languages to choose from.
is he just now becoming aware of it? it seems he had no idea something like sml existed when he first created python. i am sure he had heard of lisp/scheme but probably ignored it.
i don't understand your snark. do you honestly think python, as a programming language, is superior to something like racket or f#? these languages are newer than python of course, but the point is that they are representative of what we could be using.
It's simple, it was added to counter-balance the smug ascertainment of Guido's ignorance, and the taken-for-granted assumption that we'd be so much better if he modeled Python more after ML/Lisp/etc.
>do you honestly think python, as a programming language, is superior to something like racket or f#?
No, I think the subject is moot. Python has been adopted and is widely successful for being Python.
We had MLs and Schemes/Lisps available before and after Python and they didn't manage to get traction. Why do you think having the original Python be more like these would help its case?
Even if the result was a "better language" in the sense you think Racket or F# are, those are still niche, and there's all the reasons to believe Python would be too if it followed their model.
So, it's not "if only Python was ML/Lisp like we would now have an equally successful but better Python!".
It's more likely "if Python was ML/Lisp it would still be niche today, and we wouldn't have a language with the characteristics that people love in Python and adopted it for, but yet another ML or Lisp version".
You can do multiple dispatching in Python, by hand or with decorators, but it can get kind of awkward, not as elegant as CLOS's and Dylan's approach with generic functions.
Five-minute Multimethods in Python,
by Guido van van Rossum.
I used to believe that multimethods were so advanced I would never need them. Well, maybe I still believe that, but here's a quick and dirty implementation of multimethods so you can see for yourself. Some assembly required; advanced functionality left as an exercise for the reader.
In Perl6 multiple dispatch is a fundamental feature. Even the infix numeric addition operator is handled by 27 multi subs. (They usually get inlined or even optimised out entirely.)
say &infix:«+».candidates.elems; # 27
Here is a quick translation of that second link to Perl6
#! /usr/bin/env perl6
use v6.d;
enum Roshambo < Rock Paper Scissors >;
enum Outcome < Lose Win Draw >;
proto compete ( Roshambo, Roshambo --> Outcome ){*}
multi compete ( Paper, Rock --> Win ){}
multi compete ( Rock, Scissors --> Win ){}
multi compete ( Scissors, Paper --> Win ){}
multi compete ( $a, $b where $b eqv $a --> Draw ){}
multi compete ( $, $ --> Lose ){}
for Roshambo.roll(20) Z Roshambo.roll(20) -> ($a,$b) {
say "$a.fmt('%8s'), $b.fmt('%8s'): &compete($a,$b)"
}
(Note that I didn't really write any actual code for the `compete` subroutines; it was all handled by the signatures.)