<div dir="ltr">Hi Everyone,<div><br></div><div>Never posted in here before, so I hope that I'm not violating any particular procedure for intros or something.</div><div><br></div><div><p style="box-sizing:border-box;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";margin-top:0px">Over time, there have been various switch or match statement proposal; some that have gotten as far as PEPs:</p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">2001 Nov - <a href="https://www.python.org/dev/peps/pep-0275/" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://www.python.org/dev/peps/pep-0275/</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">2006 Jun - <a href="https://www.python.org/dev/peps/pep-3103/" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://www.python.org/dev/peps/pep-3103/</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">2014 Apr - <a href="https://groups.google.com/d/msg/python-ideas/J5O562NKQMY/DrMHwncrmIIJ" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://groups.google.com/d/msg/python-ideas/J5O562NKQMY/DrMHwncrmIIJ</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">2016 May - <a href="https://groups.google.com/d/msg/python-ideas/aninkpPpEAw/wCQ1IH5mAQAJ" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://groups.google.com/d/msg/python-ideas/aninkpPpEAw/wCQ1IH5mAQAJ</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">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.</p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">The main objections I've seen are in the following buckets:</p><ul style="box-sizing:border-box;padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol""><li style="box-sizing:border-box">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</li><li style="box-sizing:border-box;margin-top:0.25em">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.</li></ul><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">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:</p><ul style="box-sizing:border-box;padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol""><li style="box-sizing:border-box">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.</li><li style="box-sizing:border-box;margin-top:0.25em">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.</li><li style="box-sizing:border-box;margin-top:0.25em">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?"</li><li style="box-sizing:border-box;margin-top:0.25em">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.</li></ul><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">I figured maybe a good way to continue the discussion is to offer a straw-man example syntax:</p><pre style="word-wrap:break-word;white-space:pre-wrap"># Simple pattern matching
x = 1
number = match x:
1 => "one"
2 => "two"
3 => "three"
10 => "ten"
_ => "anything"
print(number) # one
# Final Pattern that matches anything
x = 3
number = match x:
1 => "one"
2 => "two"
_ => "anything"
print(number) # anything
# Pattern matching without any match returns None
number = match x:
1 => "one"
2 => "two"
print(number) # None
# Pattern matching with guards
x = 'three'
number = match x:
1 => "one"
y if y is str => f'The string is {y}'
_ => "anything"
print(number) # The string is three
# Pattern matching with multiple values
x = 1
number = match x:
1, 2, 3, 4 => "one to four"
_ => "anything"
print(number) # one to four
# Pattern matching with types
x = 1.
number = match x:
x:int => f'{x} is a int'
x:float => f'{x} is a float'
x:str => f'{x} is a string'
print(number) # x is a float
# Supports destructuring dicts
x = {'foo': 1}
number = match x:
{'foo': 1} => "foo is 1"
_ => "anything"
print(number) # foo is 1
# Supports binding with destructuring dicts
x = {'foo': 1, 'bar': 2}
number = match x:
{'foo': y} => f'got foo {y}'
{'bar': z} => f'got bar {z}'
{'foo': y, 'bar': z} => f'got foo {y} and bar {z}'
_ => "anything"
print(number) # got foo 1 and bar 2
# Supports destructuring other types too
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
point = Point(1,2)
number = match point:
Point(x,y) => f'point has an x of {x} and y of {y}'
_ => "anything"
print(number) # point has an x of 1 and y of 2</pre><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol""><br></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">As a continued defense for this specific syntax choixe, lets see how two other languages with this feature handle it. I'm going to try to offer as nearly as possible similar examples.<br></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">Scala <a href="https://docs.scala-lang.org/tour/pattern-matching.html" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://docs.scala-lang.org/tour/pattern-matching.html</a></p><pre style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;margin-top:0px;margin-bottom:16px;word-wrap:normal;padding:16px;overflow:auto;line-height:1.45;background-color:rgb(246,248,250);border-radius:3px;color:rgb(36,41,46)"><code style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;padding:0px;margin:0px;background:transparent;border-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">val x: Int = 1
def makeMatch(x: Any) = x match {
case 1 => "one"
case 2 => "two"
case _ => "anything"
}
val number = makeMatch(x)
</code></pre><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">Rust <a href="https://doc.rust-lang.org/1.5.0/book/match.html" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://doc.rust-lang.org/1.5.0/book/match.html</a></p><pre style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;margin-top:0px;margin-bottom:16px;word-wrap:normal;padding:16px;overflow:auto;line-height:1.45;background-color:rgb(246,248,250);border-radius:3px;color:rgb(36,41,46)"><code style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;padding:0px;margin:0px;background:transparent;border-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">let x = 1;
let number = match x {
1 => "one",
2 => "two",
_ => "anything",
}
</code></pre><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">And for the sake of completeness, here are other languages with similar syntax features and their associated documentation</p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">F# <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">Elixir <a href="https://elixir-lang.org/getting-started/case-cond-and-if.html" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://elixir-lang.org/getting-started/case-cond-and-if.html</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">Clojure <a href="https://github.com/clojure/core.match/wiki/Basic-usage" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://github.com/clojure/core.match/wiki/Basic-usage</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">JavaScript (ES2018?) <a href="https://github.com/tc39/proposal-pattern-matching" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://github.com/tc39/proposal-pattern-matching</a></p><p style="box-sizing:border-box;margin-top:0px;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"">Haskell <a href="https://en.wikibooks.org/wiki/Haskell/Pattern_matching" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://en.wikibooks.org/wiki/Haskell/Pattern_matching</a></p><p style="box-sizing:border-box;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";margin-bottom:0px">Swift<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html" rel="nofollow" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none">https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html</a></p></div><div><b><br></b></div><div><br></div><div><br></div><div><b><br></b></div><div><b><br></b></div></div>