Over time, there have been various switch or match statement proposal; some that have gotten as far as PEPs:
2001 Nov - https://www.python.org/dev/peps/pep-0275/
2006 Jun - https://www.python.org/dev/peps/pep-3103/
2014 Apr - https://groups.google.com/d/msg/python-ideas/J5O562NKQMY/DrMHwncrmIIJ
2016 May - https://groups.google.com/d/msg/python-ideas/aninkpPpEAw/wCQ1IH5mAQAJ
However, I don't see that the conversation ever really resolved, so I'd like restart the conversation on some kind of pattern matching syntax in Python.
The main objections I've seen are in the following buckets:
- One--and Preferably Only One--Obvious Way. Basically, we have if/elif and that's all we need, so this is syntactical sugar bloat. I'd submit that there are specific cases where this kind of syntax would be the obviously correct way to do something
- Specific Syntax Objections. There have been several specific objections that usually come down to "unreadable" or "ugly", which are subjective statements that don't really bring any good way to continue the discussion in a productive manner.
I cannot handle all syntax objections ahead of time, but I can handle the "only way" objection. At high level, pattern matching provides similar syntactical sugar to list comprehensions. We could argue that they are unnecessary since we have for loops. But more importantly, pattern matching is powerful for what it restricts you to. More specifically:
- Assignment. Many of the implementations offer the ability to immediately assign the value from the matching pattern. However, assignment is prevented in the middle of all of the patterns, which is possible in if/elif.
- No Fall Through. Once a pattern is matched, there's no way to break to try another branch. Prevents having to look at multiple cases to figure out how something resolved. If/elif can have this happen, of course, but even more confusing sometimes breaks will be mixed with returns or other control flows, which makes figuring how large if/elifs are resolved.
- Automatic Unpacking. Some implementations offer the ability unpack a dictionary equivalent automatically into keys or select ranges of values like slicing. Compared to if/elif, this is tremendously more DRY than doing the "does the key exists?" and then "what is that keys value?"
- Guards. Often times you can embed another check to go along with the simple pattern matching. Absolutely possible with if/elif, but crucially are implementations generally happen after the pattern check. Again, keeps code DRY and improves readability.
I figured maybe a good way to continue the discussion is to offer a straw-man example syntax:
{{PLACEHOLDER FOR EXAMPLES}}
As a continued defense for this specific feature, lets see how two other languages with this feature handle it. I'm going to try to offer as nearly as possible similar examples.
Scala https://docs.scala-lang.org/tour/pattern-matching.html
val x: Int = 1
def makeMatch(x: Any) = x match {
case 1 => "one"
case 2 => "two"
case _ => "anything"
}
val number = makeMatch(x)
Rust https://doc.rust-lang.org/1.5.0/book/match.html
let x = 1;
let number = match x {
1 => "one",
2 => "two",
_ => "anything",
}
And for the sake of completeness, here are other languages with similar syntax features and their associated documentation
F# https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
Elixir https://elixir-lang.org/getting-started/case-cond-and-if.html
Clojure https://github.com/clojure/core.match/wiki/Basic-usage
JavaScript (ES2018?) https://github.com/tc39/proposal-pattern-matching
Haskell https://en.wikibooks.org/wiki/Haskell/Pattern_matching