# [Python-ideas] Pattern Matching Syntax

Robert Roskam raiderrobert at gmail.com
Thu May 3 10:29:54 EDT 2018

```Hey Joao,

Thanks for providing me feedback on this idea!

For the simplistic example at that you select, yes, you absolutely can do
this as it stands atm. However, the examples I provided further along
aren't as easily accomplished, nor is something like this:

x = -1

result = match x:
x:int if x > 0 => 'greater than 0'
x:int, x:float if x == 0 => 'equal to 0'
x:int if x < 0 => 'less than 0'

print(result)  # 'less than 0'

Accomplishing the above with a just a dictionary would be not be the
current Pythonic solution, imo, you'd do it with if/elif:

x = -1
result = None

if type(x) is int and x > 0:
result =  'greater than 0'
elif (type(x) is int or type(x) is float) and x == 0:
result =  'greater than 0'
elif type(x) is int and x < 0:
result =  'greater than 0'

print(result)  # 'less than 0'

So yes, Python has the syntax to handle these problems. However, my point
is there's value in the kind of feature I'm proposing, and the value is
stated in the above proposal.

If the specific syntax choice `=>` offends the sensibilities, I simply
chose mine because a good number of other languages already use `=>`. I've
also considered the following:

->
to
then
case

And I think it would be good to hear if anyone has a specific preference
for those others.

On Thu, May 3, 2018 at 9:16 AM Joao S. O. Bueno <jsbueno at python.org.br>
wrote:

> (sorry - my aboe message is about using a dictionary - the "=>" weird
> tokens should j=be just plain ":" -
> the point is that Python açready has syntax to do what is asked)
>
> On 3 May 2018 at 10:15, Joao S. O. Bueno <jsbueno at python.org.br> wrote:
> >
> > number = match x:
> >     1 => "one"
> >     2 => "two"
> >     3 => "three"
> >     10 => "ten"
> >     _ => "anything"
> >
> > number = {
> >     1 => "one"
> >     2 => "two"
> >     3 => "three"
> >     10 => "ten"
> >     }.get(x,  "anything")
> >
> > No magic syntax with blocks starting inside an assignment, just to start
> with.
> >
> >
> > On 3 May 2018 at 09:41, Robert Roskam <raiderrobert at gmail.com> wrote:
> >> Hi Everyone,
> >>
> >> Never posted in here before, so I hope that I'm not violating any
> particular
> >> procedure for intros or something.
> >>
> >> 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 -
> >>
> >> 2016 May -
> >>
> >> 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:
> >>
> >> # 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
> >>
> >>
> >> 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.
> >>
> >> 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
> >>
> >>
> >> Swifthttps://
> developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html
> >>
> >>
> >>
> >>
> >>
> >>
> >>
> >> _______________________________________________
> >> Python-ideas mailing list
> >> Python-ideas at python.org
> >> https://mail.python.org/mailman/listinfo/python-ideas
> >> Code of Conduct: http://python.org/psf/codeofconduct/
> >>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180503/7567b608/attachment-0001.html>
```