[Python-Dev] Re: PEP 622 version 2 (Structural Pattern Matching)
Hi Larry, You are right that just dismissing intuition is wrong. I should have been more careful with my wording or explain them better, and I would like to apologise if my response came across as too strong in this regard. The actual problem that I see is that we have different cultures/intuitions fundamentally clashing here. In particular, so many programmers welcome pattern matching as an "extended switch statement" and find it therefore strange that names are binding and not expressions for comparison. Others argue that it is at odds with current assignment statements, say, and question why dotted names are _/not/_ binding. What all groups seem to have in common, though, is that they refer to _/their/_ understanding and interpretation of the new match statement as 'consistent' or 'intuitive'---naturally pointing out where we as PEP authors went wrong with our design. But here is the catch: at least in the Python world, pattern matching as proposed by this PEP is an unprecedented and new way of approaching a common problem. It is not simply an extension of something already there. Even worse: while designing the PEP we found that no matter from which angle you approach it, you will run into issues of seeming 'inconsistencies' (which is to say that pattern matching cannot be reduced to a 'linear' extension of existing features in a meaningful way): there is always something that goes fundamentally beyond what is already there in Python. That's why I argue that arguments based on what is 'intuitive' or 'consistent' just do not make sense _/in this case/_. I think the discussion on this mailing list with the often contradictory views, proposals, and counter-proposals more than makes my point. As for your argument that it looks like calling a function or creating an object: I tried to explain a little while ago that you'd be well advised to rather approach it as something similar to a function _/definition/_. After all, the part after `def` in `def foo(a, b):` also looks like a function call! But nobody seems to mind this similarity in syntax there! And the target in `(a, b) = c` looks like a tuple constructor, although it actually is the exact opposite. Finally, I completely agree that intuition is informed by experience and serving us very well. The first part of this, however, is also to say that intuition is malleable thing! And experience from other programming languages who took the leap to having pattern matching shows that it quickly becomes a quite intuitive and easy to use feature. Cheers, Tobias P.S. Please excuse my late reply; I am currently on vacation. Quoting Larry Hastings : On 7/31/20 12:36 AM, Tobias Kohn wrote: And since pattern matching is really a new feature to be introduced to Python, a feature that can be seen in different lights, there is no 'Python-Programmer intuition' that would apply in this case. It's not fair to say "intuition doesn't apply because it's new syntax". There are plenty of examples of intuition serving a Python programmer well when encountering new syntax. A Python programmer's intuition is informed by existing syntax and conventions in the language. When they see a new construct, its similarity to existing constructs can make understanding the new syntax quite intuitive indeed. Take for example list comprehensions. Python 1 programmers hadn't seen a = [x for x in y] But they knew what square brackets meant in that context, it meant "creates a new list". And they knew what "for x in y" meant, that meant iteration. Understanding those separate two concepts, a Python 1 programmer would be well on their way to guessing what the new syntax meant--and they'd likely be right. And once they understood list comprehensions, the first time they saw generator expressions and set and dict comprehensions they'd surely intuit what those did immediately. The non-intuitiveness of PEP 622, as I see it, is that it repurposes what looks like existing Python syntax but frequently has wholly different semantics. For example, a "class pattern" looks like it's calling a function--perhaps instantiating an object?--but the actual semantics and behavior is very different. Similarly, a "mapping pattern" looks like it's instantiating a dict, but it does something very different, and has unfamiliar and seemingly arbitrary rules about what is permitted, e.g. you can't use full expressions or undotted-identifiers when defining a key. Add the "capture pattern" to both of these, and a Python programmer's intuition about what this syntax traditionally does will be of little help when encountering a PEP 622 match statement for the first time. Cheers, //arry/ ___ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to
[Python-Dev] Pattern matching (alternative to PEP 622)
Hi everyone, By what I'm about to write below, I've aimed at a design to meet needs resembling those that PEP 622 deals with, although with some differences, especially in emphasis. I'm not writing a full introduction here; the intended audience of this email is people somewhat familiar with PEP 622 and its discussions. This email doesn't have much structure or anything, but I hope it's sufficiently clear. Things that this design aims to address: * Check whether an object's structure matches a given pattern * Optionally extract desired values from within that structure * Learning: patterns are understandable in a logical and consistent manner * Matching can be easily tinkered with interactively * Names used in patterns behave in a clear and intuitive way for Python programmers * ... The most difficult thing is perhaps to understand what names mean: what is being bound to, and what is a value defined elsewhere and so on. For example, if a (somewhat unrealistic) pattern looks like Point3D(x=3.14, y=6, z=_) , there are four names that refer to something: `Point3D`, `x`, `y` and `z`. To understand this, it is useful to think of the pattern as corresponding to an expression, although it is not treated as quite the same in the end. (So, here x, y, z refer to internals/arguments of Point3D) The situation becomes more difficult when the values to compare with are in variables, and/or if one wishes to extract a value from the structure. Point3D(x=pi, y=SIX, z=value) Now there is no way to tell, from this, which names refer to existing objects and which should be bound to by the operation, except by guessing. Here, `value` is supposed to be a binding target. Python already has destructuring assignment (`a, b, *rest = values`), which is similar to what happens in function calls: `def func(a, b, *rest): ...`. However, compared to this, it is more useful to see patterns as working backwards compared to this. For example, the semantics of the names in lambda value: Point3D(x=pi, y=SIX, z=value) are exactly as desired. That is, when the pattern matching is interpreted as "does this object look like what this function would produce, and if so, what would be the arguments of the function in that case?". Matching the pattern would bind to `value`. So, with this, a previous understanding of function definitions already gives you a mental model for how names work in patterns *and* for what the pattern is supposed to do. In theory, the lambda expression could BE the syntax for a pattern. However, many have wished for a different syntax even for lambdas. A slightly nicer form would be to omit the keyword `lambda`, but then one would still have to repeat the names to be bound. To avoid that, we need a way to explicitly mark "not-yet-bound names": Point3D(x=pi, y=SIX, z=value?) Before going any further, how would one invoke the matching machinery? It could be matches and that would evaluate to a boolean-like value. With this syntax, the `is_tuple` example from PEP 622 would look something like this: def is_tuple(node: Node) -> bool: if node matches Node(children=[LParen(), RParen()]): return True elif node matches Node(children=[Leaf(value="("), Node(), Leaf(value=")")]): return True return False Or something like: def is_tuple(node: Node) -> bool: if node matches tuple_pattern: return True return False Here, `tuple_pattern` would be a pattern pre-defined with a function-like syntax. Also, if there is a `tuple_pattern`, then `is_tuple` is probably not needed at all. Note that in PEP 622, is_tuple uses a match statement with three cases. So, in effect, the full tuple_pattern had been split into subpatterns. This was only possible because it was an OR pattern. In general, splitting a longer pattern into cases like that is not possible. Longer function-like patterns, on the other hand, can be expressed using more pattern functions – just like regular functions can use helper functions. Here, tuple_pattern isn't passed any arguments. It also doesn't have any parameters. However, if it did, those would be considered wildcards, as I believe we'd want both the programmer and the compiler/optimizers to explicitly see, from the match expression, which names will/would be bound. If something other than wildcard behavior is desired, that should be explicitly specified in a "pattern function call". Let's take another example pattern: pdef main_diagonal_point(pos): return Point3D(pos, pos, pos) Now, `main_diagonal_point(0)` would refer to the origin, and `point matches main_diagonal_point` would be true for every point with `x == y == z`. Similarly, also `point matches main_diagonal_point(pos?)` should only match if `x == y == z` — and then bind that value to `pos`. However, one might expect to be able to write the same thing inline as point matches Point3D(pos?, pos?, pos?) , so based on that, multiple occurrences of the same binding target should ensure
[Python-Dev] Re: PEP 622 version 2 (Structural Pattern Matching)
On Thu, 16 Jul 2020 at 19:09, Richard Damon wrote: > One question that comes to mind, does match NEED a colon at the end of it? If > it didn’t have the colon, it wouldn’t need the indent for the following lines. Or something like match t case ("rect", real, imag): return complex(real, imag) case ("polar", r, phi): return complex(r * cos(phi), r * sin(phi)) else: pass -- Kind regards, Stefano Borini ___ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/G6HNAS4TMH6DY6QTAYXUZJK5GIRI3MC5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-Dev] Re: PEP 624: Remove Py_UNICODE encoder APIs
On Tue, Aug 4, 2020 at 3:31 PM M.-A. Lemburg wrote: > > Hi Inada-san, > > thanks for attending EuroPython. I won't be back online until > next Wednesday. Would it be possible to wait until then to continue > the discussion ? > Of course. The PEP is for Python 3.11. We have a lot of time. Bests, -- Inada Naoki ___ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/YSRQWCOGXHFL6BOYBAFGW72YOTRII5AR/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-Dev] Re: PEP 624: Remove Py_UNICODE encoder APIs
Hi Inada-san, thanks for attending EuroPython. I won't be back online until next Wednesday. Would it be possible to wait until then to continue the discussion ? Thanks, -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts >>> Python Projects, Coaching and Consulting ... http://www.egenix.com/ >>> Python Database Interfaces ... http://products.egenix.com/ >>> Plone/Zope Database Interfaces ... http://zope.egenix.com/ ::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/ http://www.malemburg.com/ On 04.08.2020 05:13, Inada Naoki wrote: > Hi, Lemburg. > > Thank you for organizing the EuroPython 2020. > I enjoyed watching some sessions from home. > > I think current PEP 624 covers all your points and ready for Steering > Council discussion. > Would you like to review the PEP before it? > > Regards, > > > On Thu, Jul 9, 2020 at 8:19 AM Inada Naoki wrote: >> >> On Thu, Jul 9, 2020 at 5:46 AM M.-A. Lemburg wrote: >>> - the fact that the encode APIs encoding from a Unicode buffer >>> to a bytes object; this is an important fact, since the removal >>> removes access to this codec functionality for extensions >>> >>> - PyUnicode_AsEncodedString() is not a proper alternative, since >>> it requires to create a temporary PyUnicode object, which is >>> inefficient and wastes memory >> >> I wrote your points in the "Alternative Idea > Replace Py_UNICODE* >> with Py_UCS4* " >> section. I wrote "User can encode UCS-4 string in C without creating >> Unicode object." in it. >> >> https://www.python.org/dev/peps/pep-0624/#replace-py-unicode-with-py-ucs4 >> >> Note that the current Py_UNICODE* encoder APIs create temporary >> PyUnicode objects. >> They are inefficient and wastes memory now. Py_UNICODE* may be UTF-16 on some >> platforms (e.g. Windows) and builtin codecs don't support UTF-16 input. >> >> >>> >>> - the maintenance effect mentioned in the PEP does not really >>> materialize, since the underlying functionality still exists >>> in the codecs - only access to the functionality is removed >>> >> >> In the same section, I described the maintenance cost as below. >> >> * Other Python implementations may not have builtin codec for UCS-4. >> * If we change the Unicode internal representation to UTF-8, we need >> to keep UCS-4 support only for these APIs. >> >>> - keeping just the generic PyUnicode_Encode() API would be a >>> compromise >>> >>> - if we remove the codec specific PyUnicode_Encode*() APIs, why >>> are we still keeping the specisl PyUnicde_Decode*() APIs ? >>> >> >> OK, I will add "Discussions" section. (I don't like "FAQ" because some >> question >> are important even if it is not "frequently" asked.) >> >> Quick answer is: >> >> * They are stable ABI. (Py_UNICODE is excluded from stable ABI). >> * Decoding from char* is more common and generic use case than encoding from >> Py_UNICODE*. >> * Other Python implementations using UTF-8 as internal representation >> can implement >> it easily. >> >> But I'm not opposite to remove it (especially for minor UTF-7 codec). >> It is just out of scope of this PEP. >> >> >>> - the deprecations were just done because the Py_UNICODE data >>> type was replaced by a hybrid type. Using this as an argument >>> for removing functionality is not really good practice, when >>> these are ways to continue exposing the functionality using other >>> data types. >> >> I hope the "Replace Py_UNICODE* with Py_UCS4* " section describe this. >> >> Regards, >> >> -- >> Inada Naoki > > > ___ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/WZYG5X3MMJX6B7LWO6FXIJEORSYJSQYK/ Code of Conduct: http://python.org/psf/codeofconduct/