<div dir="auto"></div><br><div class="gmail_quote"><div dir="ltr">Le mar. 18 sept. 2018 à 13:39, Tobias Kohn <<a href="mailto:kohnt@tobiaskohn.ch">kohnt@tobiaskohn.ch</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><u></u>
<div style="font-family:Arial;font-size:14px"><p>Hello Everyone,<br>
<br>
Please excuse my being late for properly responding to the last thread on "Pattern Matching Syntax" [1].  As Robert Roskam has already pointed out at the beginning of that thread, there has been much previous discussion about adding pattern matching to Python, and several proposals exist.  It is therefore not my intention to propose yet another syntax choice for pattern matching, but more to share my experience with implementing it, in the hope of making a worthwhile contribution to the overall discussion.<br>
<br>
This summer, I basically ended up requiring pattern matching in Python for a research project I am working on.  Some initial hacks have then grown into a library for pattern matching in Python [2].  On the one hand, my design is certainly heavily influence by Scala, with which I also work on a regular basis.  On the other hand, I ran into various difficulties, challanges, and it has been particularly important to me to find a design that blends well with Python, and harnesses what Python already offers.<br>
<br>
I have written down my experience in the form of a discussion on several options concerning syntax [3], and implementation [4], respectively.  As the articles have turned out longer than I originally intended, it might take up too much time for those who have little interest in this matter in the first place.  However, considering that the subject of pattern matching has been coming up rather regularly, my experience might help to contribute something to the discussion.  Let me provide a brief summary here:<br>
<br>
<strong>1. Pattern Matching is not Switch/Case</strong><br>
--------------------------------------<br>
When I am talking about pattern matching, my goal is to do a deep structural comparison, and extract information from an object.  Consider, for instance, the problem of optimising the AST of a Python program, and eliminate patterns of the form `x + 0`, and `x - 0`.  What pattern matching should be offering here is a kind of comparison along the lines of:<br>
<span style="font-family:courier new,courier,monospace">`if node == BinOp(?, (Add() or Sub()), Num(0)): ...`</span><br>
Ideally, it should also return the value of what is marked by the question mark `?` here, and assign it to a variable `left`, say.  The above comparison is often written as something like, e. g.:<br>
<span style="font-family:courier new,courier,monospace">`case BinOp(left, Add()|Sub(), Num(0)): ...`</span><br>
This use of `<span style="font-family:courier new,courier,monospace">case</span>`, however, is not the same as a switch-statement.<br>
<br>
<strong>2. Orthogonality</strong><br>
----------------<br>
Getting the syntax and semantics of nested blocks right is hard.  Every block/suite in Python allows any kind of statements to occur, which allows for things like nested functions definitions, or having more than just methods in a class.  If we use a two-levelled block-structure, we run into the problem of finding good semantics for what the following means (note the variable `x` here):<br>
```<br>
<span style="font-family:courier new,courier,monospace">match node:<br>
    x = 0<br>
    case BinOp(left, Add(), Num(0)):<br>
        ...<br>
    x += 1<br>
    case BinOp(left, Mul(), Num(1)):<br>
        ...</span><br>
```<br>
In the case of a "switch block", such additional statements like the `x=0`, and `x+=1` can become quite problematic.  On the other hand, requiring all statements inside the block to be case-statements violates the orthogonality found otherwise in Python.<br>
<br>
I feel that this dilemma is one of the core issues why the syntax of switch statements, or pattern matching seems so exceptionally hard.  In the end, it might therefore, indeed, make more sense to find a structure that is more in line with if/elif/else-chains.  This would lead to a form of pattern matching with little support for switch-statement, though.<br>
<br>
<strong>3. Implementation</strong><br>
-----------------<br>
For the implementation of pattern matching, my package compiles the patterns into context-manager-classes, adds these classes in the background to the code, and then uses `with`-statements to express the `case`-statement.  If have found a neat way to make the execution of a `with`-statement's body conditional.<br>
<br>
Two things have been curcially important in the overall design: first, the "recompilation" cannot change the structure of the original code, or add any line.  This way, all error messages, and tooling should work as expected; the invasive procedure should be as minimal as possible.  Second, it is paramount that the semantics of how Python works is being preserved.  Even though the actual matching of patterns is done in external classes, all names must be resolved "locally" where the original `case`-statement lives.  Similarly, the variables defined by the pattern are to local variables, which are assigned if, and only if, the pattern actually matches.<br>
<br>
Should pattern matching ever be added to Python properly, then there will be no need to use `with`-statements and context managers, of course.  But the implementation must make sure, nonetheless, that the usual semantics with name resolving of Python is being respected.<br>
<br>
<strong>4. Syntax of Patterns</strong><br>
---------------------<br>
The syntax of patterns themselves has been guided by two principles (again).  First, if there is a way to already express the same thing in Python, use that.  This applies, in particular, to sequence unpacking.  Second, patterns specify a possible way how the object in question could have been created, or constructed in the first place.  Hence, it is no accident that the pattern `BinOp(left, Add(), Num(0))` above looks almost like a constructor.<br>
<br>
Other implementation are happy to redefine the meanings of operators like `in`, or `is` (as in, e. g., `case x is str:`).  While this might look very convenient at first, it will most probably lead to many subsequent bugs where people write `if x is str:` to mean the same thing (namely test the type of `x`).  Even though expressing patterns requires reusing some operators in a new way, we have to extremely careful to choose widely, and minimise confusion, and surprises.<br>
<br>
<br>
Pattern matching could certainly make a great addition to Python, and various current implementations act as proof of concepts.  However, choosing an appropriate syntax for pattern matching is hard, and we should work hard to make sure that any such addition feels natural in Python, even at the expense of having to write more, and being not as terse as other languages.<br>
<br>
I hope my thoughts in this matter can make a worthwhile constribution to the discussion.  And I would like to emphasise once more, that my goal is not to propose a new syntax for pattern matching, but to report on my experience while implementing it.<br>
<br>
Kind regards,<br>
Tobias Kohn<br>
<br>
<br>
[1] <a href="https://groups.google.com/d/topic/python-ideas/nqW2_-kKrNg/discussion" target="_blank" rel="noreferrer">https://groups.google.com/d/topic/python-ideas/nqW2_-kKrNg/discussion</a><br>
[2] <a href="https://github.com/Tobias-Kohn/pyPMatch" target="_blank" rel="noreferrer">https://github.com/Tobias-Kohn/pyPMatch</a><br>
[3] <a href="https://tobiaskohn.ch/index.php/2018/09/18/pattern-matching-syntax-in-python/" target="_blank" rel="noreferrer">https://tobiaskohn.ch/index.php/2018/09/18/pattern-matching-syntax-in-python/</a><br>
[4] <a href="https://tobiaskohn.ch/index.php/2018/09/12/implementing-pattern-matching/" target="_blank" rel="noreferrer">https://tobiaskohn.ch/index.php/2018/09/12/implementing-pattern-matching/</a><br>
</p></div>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank" rel="noreferrer">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>