[HN Gopher] Pattern Matching Accepted for Python
       ___________________________________________________________________
        
       Pattern Matching Accepted for Python
        
       Author : eplanit
       Score  : 214 points
       Date   : 2021-02-09 18:16 UTC (4 hours ago)
        
 (HTM) web link (lwn.net)
 (TXT) w3m dump (lwn.net)
        
       | jjice wrote:
       | I'm mixed on this one. While I love pattern matching in SML and
       | Rust, I don't know if it's right for Python.
       | 
       | Like other comments have said, I loved and learned a lot of
       | Python from looking at a code base and understanding everything
       | immediately because there wasn't much to learn on the language
       | end of things. It was nice and small. Not that the addition of
       | pattern matching is a death sentence for simplicity, but I fear
       | that it may lead to some other extraneous features in the future.
       | 
       | I like powerful, featureful languages, but I personally like
       | Python as a simple language that anyone can learn 80% of in a
       | busy weekend.
       | 
       | Will I use pattern matching? Maybe. I'll definitely play around
       | with it. Now if we could get some algebraic datatypes then I
       | think I'd start contradicting myself...
        
       | toxik wrote:
       | Wow, this is perhaps the worst idea introduced to Python in a
       | long time. So many ambiguities, so much inscrutable syntax. What
       | a shame.
        
       | superbcarrot wrote:
       | > There should be one-- and preferably only one --obvious way to
       | do it.
       | 
       | Unless we keep adding more ways to do the same thing of course.
        
         | adamdusty wrote:
         | There have always been 100 ways to do everything in python.
         | People just constantly spout the zen thing to look smart.
        
           | superbcarrot wrote:
           | There have been multiple ways to do the same thing but that
           | shouldn't be an excuse to keep adding features that don't
           | contribute anything meaningful apart from expanding the
           | syntax.
           | 
           | The zen thing is cited so much because it's often
           | inconsistent the language itself.
        
       | jonnycomputer wrote:
       | ...
       | 
       | I'll take my down votes. Please move on opinionated HN-ers.
        
         | [deleted]
        
         | messe wrote:
         | By that same logic wouldn't                  def f(x):
         | 
         | look too close to function invocation for your taste?
        
           | [deleted]
        
       | fmakunbound wrote:
       | > After much deliberation, the Python Steering Council is happy
       | to announce that we have chosen to accept PEP 634, and its
       | companion PEPs 635 and 636, collectively known as the Pattern
       | Matching PEPs
       | 
       | This is why I'm still enamored with Lisp. One doesn't wait around
       | for the high priests to descent from their lofty towers of much
       | deep pontification and debate with shiny, gold tablets inscribed
       | with how the PEPs may be, on behalf of the plebes. One just adds
       | new language feature themselves, eg. pattern matching[1] and
       | software transactional memory[2].
       | 
       | 1. https://github.com/guicho271828/trivia
       | 
       | 2. https://github.com/cosmos72/stmx
        
       | antman wrote:
       | People complain on external corporate capture e.g. Microsoft's
       | embrace, extend, extinguish but I see a more common pattern of
       | introducing internal corporate complexity driving socially
       | powered projects to oblivion. Drupal's extension system a few
       | years back, Firefox addon ecosystem destruction, Python features
       | after 3.8 and many others.
       | 
       | People that contribute are not infinite and those initial more
       | active contributors get demoralized supporting work over a moving
       | foundation.
       | 
       | Why not put up an effort on speeding things up, removing the GIL.
       | Important and stale issues of the language that users really care
       | about. F strings where good tho. That's it. Async syntax? Less
       | good. This pattern matching thing? Have fun debugging this.
        
         | jjoonathan wrote:
         | > Firefox addon ecosystem destruction
         | 
         | I _love_ that I can install an extension without restarting,
         | and as much as I sympathize with the pet projects that got
         | dumped, I think it would have been a huge mistake to hold that
         | up just to keep dead extensions in zombie mode rather than
         | grave mode.
        
         | marcinzm wrote:
         | >Firefox addon ecosystem destruction
         | 
         | Firefox suffered greatly in marketshare because they didn't
         | pull the plug soon enough but rather gained a reputation for
         | slowness and bugginess. Doing nothing isn't a viable strategy
         | when you have competitors (ie: Chrome) who are doing something.
        
       | oflannabhra wrote:
       | Pattern matching is what I missed most when switching from Swift
       | to Python a year ago. Really happy to see this day come!
        
       | mjburgess wrote:
       | Can anyone confirm this is actual pattern matching and not the
       | frankly ridiculous procedural version that was originally
       | proposed?
       | 
       | That proposal, to deliberately hobble pattern matching by making
       | it a statement, was an egregious ideological campaign with
       | genuinely absurd consequences.
        
         | dflock wrote:
         | It's this: https://www.python.org/dev/peps/pep-0634/ - not sure
         | which version that is?
        
         | nneonneo wrote:
         | Not sure what you mean, but the accepted PEP does appear to be
         | a statement. What was the alternative?
        
           | the_duke wrote:
           | In many languages match is an expression, so you can do
           | things like `x = match y { ... }`, which is a very common use
           | case.
           | 
           | I don't write much Python these days, but it being a
           | statement rather than an expression is disappointing
           | 
           | It forces you to use a separate "output" variable or
           | `return`.
        
           | klyrs wrote:
           | I presume that the alternative to a statement is an
           | expression. For example, the ternary operator
           | x = (a if c else b)
           | 
           | is an expression, where the conditional equivalent
           | if c:            x = a        else:            x = b
           | 
           | is a statement.
        
         | galkk wrote:
         | match is a statement, but the syntax is very readable.
         | 
         | https://www.python.org/dev/peps/pep-0636/#adding-conditions-...
        
       | techdragon wrote:
       | I've followed these things over the years. Had many discussions
       | with people, including a few Python luminaries, but I honestly
       | never expected this day would come. I fell in love with pattern
       | matching when I learned Erlang and Elixir and it's bugged me ever
       | since that I didn't have any built in equivalent in Python, until
       | now!
        
         | toxik wrote:
         | This is not truly Erlang style pattern matching. And Python can
         | never have that either because of its design.
        
         | macintux wrote:
         | Python 2 had pattern matching on tuples in function arguments;
         | I was quite annoyed, coming from Erlang, when I discovered that
         | was dropped in 3.0, in part because "no one uses it".
        
       | [deleted]
        
       | hannibalhorn wrote:
       | The accepted PEP is 634:
       | https://www.python.org/dev/peps/pep-0634/ and the tutorial has
       | some examples: https://www.python.org/dev/peps/pep-0636/ .
        
       | JNRowe wrote:
       | [Expanding my comment from another post on this1]
       | 
       | Direct links to the PEPs themselves, to perhaps save others a
       | little time. Although the LWN write up linked in TFA is a very
       | nice introduction to the topic and its _big_ discussion in the
       | community.
       | 
       | Accepted:
       | 
       |  _Specification_ https://www.python.org/dev/peps/pep-0634/
       | 
       |  _Motivation and Rationale_
       | https://www.python.org/dev/peps/pep-0635/
       | 
       |  _Tutorial_ https://www.python.org/dev/peps/pep-0636/
       | 
       | Rejected:
       | 
       |  _Unused variable syntax_
       | https://www.python.org/dev/peps/pep-0640/
       | 
       |  _Explicit Pattern Syntax for Structural Pattern Matching_
       | https://www.python.org/dev/peps/pep-0642/
       | 
       | 1 https://news.ycombinator.com/item?id=26073700
        
       | properdine wrote:
       | I am so excited for this.
       | 
       | I love Python, but as of 2016, I was missing:
       | 
       | 0. Pattern matching 1. Easy support for types & type-checking
       | (thanks mypy + annotations) 2. Better string formatting (yay
       | f-strings)
       | 
       | And the nice part is that these are all relatively opt-in
       | features. So excited to be able to using pattern matching as part
       | of the language!
        
       | TrianguloY wrote:
       | Can't wait to see all the errors and questions when users start
       | using this for the missing switch statement, and not realizing it
       | doesn't work for non-dotted constants.
       | 
       | Because if I didn't misunderstood, this is not correct, is it?
       | NOT_FOUND = 404       OK = 200            match getCode():
       | case NOT_FOUND:               return default()           case OK:
       | return response()
        
         | vitus wrote:
         | Correct.
         | 
         | > Patterns may use named constants. These must be dotted names
         | to prevent them from being interpreted as capture variable:
         | 
         | NOT_FOUND would always match as a capture variable, so you'd
         | always return default().
         | 
         | I fully expect this to be covered by linters, but not with
         | further language support.
        
           | mvolfik wrote:
           | yeah, I would also expect the linters to catch this. has some
           | way to allow use of non-dotted constants been considered?
           | something like window.global_variable in JavaScript? Or would
           | I need to do something like this:?                 NOT_FOUND
           | = 404       m = {"NOT_FOUND": NOT_FOUND}       match value:
           | case m["NOT_FOUND"]:           pass
        
             | TrianguloY wrote:
             | I may be wrong, but after reading the grammar I think your
             | example is a syntax error. You can't access an element! A
             | pattern syntax is completely different to a normal
             | expression, and there is apparently no array access.
        
               | mvolfik wrote:
               | hmm, so I would need to use some namespace class https://
               | docs.python.org/3.8/library/types.html#types.SimpleN...
        
         | [deleted]
        
         | AlexandrB wrote:
         | Yup, that's what the PEP seems to suggest.
         | 
         | This along with mutable default values is going to be one of
         | the nastier Python warts.
        
           | toxik wrote:
           | Not to mention that expressions after the case keyword have
           | completely different semantics from expressions ANYWHERE
           | else. a | b is not the bitwise or of a with b.
        
             | vitus wrote:
             | You can already define __or__ to do whatever you want!
             | 
             | This is already special-cased in the standard library for,
             | say, set union (where admittedly the concept is more
             | similar to bitwise or).
        
               | toxik wrote:
               | ... except in case expressions
               | 
               | Thanks for proving my point though!
        
       | eli_gottlieb wrote:
       | Well this is some exciting news! algebraic-data-types is my most
       | commonly imported "optional" pip, after the stuff that's strictly
       | necessary for my domain (ie: PyTorch, matplotlib, and such). I
       | guess combined with dataclasses, I can basically finally write
       | ADTs properly in "native" Python.
        
       | rossdavidh wrote:
       | So, regardless of one's feelings on this particular feature, I
       | think we can see what the loss of a BDFL means: feature bloat. It
       | was once one of the core tenets of python that there be one, best
       | way to do a given thing, because that meant that when you read
       | _another_ programmer's code, you could usually understand it
       | easily. This is as opposed to languages like Perl, javascript, or
       | R, which for all their great traits are each essentially several
       | different languages masquerading as a one.
       | 
       | It's probably inevitable, once you do not have a single person to
       | say no to new features for things that can already be done, that
       | you end up with feature bloat. So, no need to rant about it. But
       | it does effectively demonstrate what the impact of a BDFL is, and
       | what is missing once you don't have one (or at any rate he's not
       | really D any more).
        
         | pmiller2 wrote:
         | Did you notice that Guido was one of the authors of the pattern
         | matching PEP?
        
           | rossdavidh wrote:
           | ha! Nope!
        
       | pansa2 wrote:
       | IMO the match statement has some very unintuitive behaviour:
       | match status:             case 404:                 return "Not
       | found"              not_found = 404         match status:
       | case not_found:                 return "Not found"
       | 
       | The first checks for equality (`status == 404`) and the second
       | performs an assignment (`not_found = status`).
        
         | _nosewings_ wrote:
         | This is how pattern matching works in any language (except for
         | some niche languages that allow nonlinear patterns, like
         | Curry).
         | 
         | Many of the comments here reveal a bizarre parochialism.
        
         | [deleted]
        
         | dpritchett wrote:
         | Are you sure the second one isn't just declaring not_found as a
         | stand-in for 404 so the case statement two lines below can
         | refer to business logic rather than a "magic" constant?
         | 
         | I would NOT expect for the line "case not_found:" to reassign
         | the status variable to 404 regardless of what it was before.
         | 
         | I can't see how or why that would be intended behavior.
        
           | dpritchett wrote:
           | I'd like to believe that the reassignment doesn't apply in
           | cases where
        
         | [deleted]
        
         | danaliv wrote:
         | Oh, yikes. I understand what's happening here but this is going
         | to bite a lot of people.
         | 
         | I might be misreading the grammar but it looks like you can
         | produce the desired effect by using an attribute, e.g. the
         | following would perform an equality check, not an assignment:
         | match status:           case requests.codes.not_found:
         | return "Not found"
         | 
         | The tutorial seems to confirm this: "This will work with any
         | dotted name (like math.pi). However an unqualified name (i.e. a
         | bare name with no dots) will be always interpreted as a capture
         | pattern"
        
           | [deleted]
        
           | TrianguloY wrote:
           | Yes, apparently your example will work correctly.
           | 
           | Now think what will happen if you need to move that not_found
           | variable to the same file as that code (so it will no longer
           | be a dotted name). If you do it manually you need to be extra
           | careful, if you use an automatic tool either it will reject
           | the change or will need to create a dummy class or something
           | in the process.
        
         | The_rationalist wrote:
         | Why is it performing an implicit assignment instead of an
         | equality check?
        
           | SrslyJosh wrote:
           | A bit part of the appeal of pattern matching in other
           | languages is support for destructuring, where you implicitly
           | assign variables to members of a data structure you're
           | performing a match on. For example, in ML-ish pseudocode:
           | 
           | len([]) = 0 len([first|rest]) = 1 + len(rest)
           | 
           | That's a trivial example. The second PEP (pattern matching
           | tutorial) has several other examples:
           | 
           | https://www.python.org/dev/peps/pep-0636/#matching-
           | multiple-...
           | 
           | So, if you use a variable in a pattern, it's an implicit
           | assignment. If you use a literal, it's a value to be matched
           | against.
           | 
           | I agree that the trivial case (a single variable with no
           | conditions) may be confusing before you know what's going on,
           | but I think the alternative, where a single variable is a
           | comparison but multiple variables (or a structure) is an
           | assignment isn't necessarily better.
        
         | [deleted]
        
         | breuleux wrote:
         | That's not too bad if it would be a syntax error to either set
         | or shadow an existing variable with the match statement.
         | Apparently it isn't, which is concerning. Personally I think I
         | may have preferred something like:                   match
         | status:             case == not_found:  # Check for equality
         | ...              match status:             case as not_found:
         | # bind status to variable not_found                 ...
         | 
         | At least the former should be an option instead of using a
         | dotted name IMO.
         | 
         | You know, a lot of potentially confusing behavior would be
         | avoided if programming languages had the sense to make
         | variables read-only by default and disallow variable shadowing
         | altogether.
        
           | willcipriano wrote:
           | I've been scanning the docs and this syntax is hard for me to
           | understand, however your version makes sense right on first
           | glance. I'd go with that.
        
         | antman wrote:
         | That looks pretty counter intuitive even after this explanation
        
         | frou_dh wrote:
         | I think the general criticism of the match statement is just
         | baggage from C overexposure. See the keyword "case" and the
         | brain immediately snaps to thinking we're in a bog-standard
         | C-style switch statement.
         | 
         | It's not a switch! Nowhere does it say switch. It's structural
         | pattern matching!
         | 
         | EDIT: The lack of block scoped variable thing does seem like a
         | wart right enough.
        
           | brianberns wrote:
           | OK, but from a functional programming point of view (where
           | structural pattern matching comes from), "case" should bind a
           | value to a name, not mutate the value of an existing
           | variable. That seems nuts to me.
        
             | thomasahle wrote:
             | Does it shadow the outside variable or mutate it?
        
               | pansa2 wrote:
               | Mutates it. Python `match` statements do not introduce a
               | new scope.
        
             | hmry wrote:
             | I don't get it, isn't that exactly what it's doing here?
        
               | magnusmundus wrote:
               | It's mutating (not shadowing) `not_found` with the value
               | of `status`. That can cause trouble if you rely on
               | `not_found` keeping the initial value later somewhere.
               | Which you would, e.g. with the global constant of
               | `NOT_FOUND`.
               | 
               | Honestly I think the issue is so troublesome only if
               | there's a single case to match, though. With more
               | expected cases it should cause pretty obvious bugs (easy
               | to catch).
        
           | [deleted]
        
           | [deleted]
        
         | airstrike wrote:
         | Yes, and this is incredibly disappointing.
         | 
         | Couldn't we achieve the same functionality with a little less
         | ambiguity using the following syntax?:
         | not_found = 404         match status:             case
         | not_found:                 return "Not found"
         | case _ as foo:                 do_something(foo)
         | return "Match anything"
         | 
         | it even works for the example in PEP 365
         | match json_pet:             case {"type": "cat", "name": _ as
         | name, "pattern": _ as pattern}:                 return
         | Cat(name, pattern)             case {"type": "dog", "name": _
         | as name, "breed": _ as breed}:                 return Dog(name,
         | breed)             case _:                 raise
         | ValueError("Not a suitable pet")
        
         | rwmj wrote:
         | That's how structural pattern matching works in ML-like
         | languages, where it's been in use for 40+ years.
        
           | [deleted]
        
           | AlexandrB wrote:
           | Don't those languages typically have immutable variables so
           | you would not be able to rebind a constant by accident?
        
             | [deleted]
        
             | the_duke wrote:
             | This is usually orthogonal to mutability.
             | 
             | In other languages that support match, whether functional
             | or not, you are not changing the value of the variable, but
             | you are shadowing/rebinding the identifier inside the scope
             | of the match clause.
        
               | pansa2 wrote:
               | Python `match` statements do not introduce a new scope.
               | 
               | The second example does indeed change the value of
               | `not_found`.
        
               | the_duke wrote:
               | That's a very problematic design decision, imo...
        
               | rwmj wrote:
               | Oh dear, that is indeed very bad.
        
               | mbo wrote:
               | What's the rationale for not introducing a new scope?
               | 
               | The only clause I can find in the PEP is
               | 
               | > A capture pattern always succeeds. It binds the subject
               | value to the name using the scoping rules for name
               | binding established for named expressions in PEP 572.
               | (Summary: the name becomes a local variable in the
               | closest containing function scope unless there's an
               | applicable nonlocal or global statement.)
               | 
               | This seems... incredibly bad.
        
               | deathanatos wrote:
               | That works the same as the rest of the language, doesn't
               | it?
               | 
               | (That is, for, if, while, etc. _also_ don 't introduce
               | new scopes.)
        
               | magnusmundus wrote:
               | It's consistent with how scoping works in loops and
               | `with` clauses. Agreed that it's more problematic here,
               | though.
        
               | pdw wrote:
               | "Introducing a new scope" is not a concept that exists in
               | Python, you only have function scope and module scope.
        
               | pansa2 wrote:
               | There are some exceptions to this - for example, the
               | iteration variable(s) in a list comprehension are only in
               | scope within the comprehension.
        
               | [deleted]
        
         | TrianguloY wrote:
         | I just wrote a comment with the same complain and similar
         | example!
         | 
         | I also think the same as you wrote, the second check will be a
         | hard to spot mistake
        
           | magnusmundus wrote:
           | I think your example makes it clearer that it won't be a very
           | subtle a bug to find, but rather completely broken behaviour
           | where only the first case is ever triggered. That should be
           | much simpler to test against. Granted, this breaks down if
           | you're matching by the number of values, possibly other
           | cases.
           | 
           | To be honest, I feel I like the (sort-of-) "forced
           | namespacing" of matching constants this brings. It should be
           | an easy habit to discipline too, the rule being very simple:
           | 
           | "if you don't want to use literals in your matching, you
           | _must_ plug them in an enumeration "
           | 
           | Too bad that enumeration can't be a PEP 435 enum without
           | adding an ugly `.value` accessor to each case, though.
        
       | Barrin92 wrote:
       | I absolutely love it. Pattern matching is one of my favourite
       | things about ML type languages and I'm glad that it's gradually
       | making its way into other languages.
       | 
       | I don't share the concerns about simplicity. It is easy to read
       | in my opinion and adds a lot of expressiveness in a relatively
       | straight forward way.
        
       | AlexandrB wrote:
       | A lot of early Python's appeal was in its simplicity. I miss that
       | era. Soon Python is going to resemble C++'s bloated feature set
       | where you're not supposed to use parts of the language because
       | "that's the old way of doing things".
       | 
       | Edit: Actually that's already true with string formatting.
        
         | 01100011 wrote:
         | Maybe the problem with C++ is that it tries too hard to
         | preserve backwards compatibility? I think it makes some of the
         | newer features clunkier. If the C++ standards folks did
         | something like Google's Abseil and provided an upgrade tool
         | while discontinuing old features they might have ended up with
         | a better language. I understand something like that might not
         | work for everyone, but from what I've gathered in talking to
         | other devs, there is a strong distaste for the current state of
         | C++.
        
         | 74d-fe6-2c6 wrote:
         | I need to justify six digits in Germany - we're not the Bay
         | Area.
        
         | _jjkk wrote:
         | I agree completely.
         | 
         | I hate how different reading C++0x and C++17 is. I hate reading
         | a "C++ style guide" for a new project.
         | 
         | I already feel that pretty soon, "Python Style Guide" will be a
         | necessary evil...
        
           | atoav wrote:
           | Really? I program Python for over a decade now and compared
           | to other language it was always the one where style somewhat
           | was the smallest issue with that language (compared to the C,
           | C++, C#, Javascript, Java I have seen).
           | 
           | Might be that the whitespace indentations focus the mind.
           | Also: PEPs _already_ act as style guides. And if you are
           | worried to do it wrong, just run it through a code formatter
           | like black. It really isn 't that much of a problem IMO.
        
             | roelschroeven wrote:
             | I think grandparent is talking about something else. Large
             | C++ codebases often have a guide that says which parts of
             | the language to use and not to use. That can be useful if
             | you have a team with people with different levels of
             | expertise in the language, or expertise in different parts
             | of the language. C++ has grown to be a language with _a
             | lot_ of different parts to choose from.
             | 
             | And it looks like Python is heading in the same direction.
             | It's not difficult to imagine a future where some Python
             | projects are going to want such guides too.
        
               | 533474 wrote:
               | grandparent?
        
               | roelschroeven wrote:
               | The parent comment of the parent of my comment, and by
               | extension the writer of that comment.
        
               | atoav wrote:
               | Thanks for the clarification.
        
         | nickysielicki wrote:
         | Already true with string formatting, map/filter versus
         | comprehensions, plenty of other things.
         | 
         | Find me a modern language where that isn't true, though.
        
         | scatters wrote:
         | And packaging!
        
         | superbcarrot wrote:
         | It's difficult to balance it out correctly. F-strings were a
         | significant improvement and I still think it was a great idea
         | to include them and trade off some of the language simplicty
         | for the added convenience. This new pattern matching... I'm not
         | convinced yet.
        
           | roelschroeven wrote:
           | Personally I don't feel f-strings are an improvement at all,
           | but I think I can see why people prefer them. But a
           | significant improvement, that I don't see at all. Can someone
           | explain why e.g.                   f'gcd({a}, {b}) =
           | {math.gcd(a, b)}'
           | 
           | is so much better than                   'gcd({}, {}) =
           | {}'.format(a, b, math.gcd(a, b))
           | 
           | In the .format() version, the formatting and the values are
           | separate and that makes it more clear to see both the
           | formatting and the values. I really like that separation.
           | When the expressions get more complex, .format() doesn't
           | really lose any clarity while f'' gets pretty unreadable
           | quite fast IMO. Yes, you can simplify by assigning the
           | expressions to variables, but .format() doesn't even need
           | that.
        
             | cjohnson318 wrote:
             | Once you get over five arguments in str.format(), it gets
             | weird. I reverse engineered a product that required a lot
             | of string formatting, and f strings made things more
             | readable and debuggable.
        
             | superbcarrot wrote:
             | I find the f-string version better because I read from left
             | to right and find it unnatural when my eyes need to jump
             | around several times over the same expression in order to
             | parse it. In your example that effect isn't too strong
             | because there isn't a lot of additional text in the string
             | and it's very clear what's going on either way.
        
             | IanCal wrote:
             | > In the .format() version, the formatting and the values
             | are separate and that makes it more clear to see both the
             | formatting and the values.
             | 
             | It makes it harder to see which values actually go where
             | though. I really dislike the separation.
        
               | thaumasiotes wrote:
               | > It makes it harder to see which values actually go
               | where though.
               | 
               | You can name the variables in the format string and then
               | pass the expressions as keyword parameters.
        
               | ju_sh wrote:
               | Thank goodness we still have both ;)
        
               | roelschroeven wrote:
               | > I really dislike the separation.
               | 
               | That's obviously a pretty fundamental difference in
               | point-of-view. And it looks like your point-of-view is
               | shared by a large majority.
               | 
               | "The reasonable man adapts himself to the world. The
               | unreasonable man persists in trying to adapt the world to
               | himself. Therefore, all progress depends on the
               | unreasonable man." -- George Bernard Shaw
               | 
               | I try to be reasonable, so I guess I should try to come
               | to terms with f-strings. In any case please don't depend
               | on more progress.
        
         | not_knuth wrote:
         | Obligatory Bjarne Stroustrup quote:
         | 
         |  _" There are only two kinds of languages: the ones people
         | complain about and the ones nobody uses."_
         | 
         | I think it's an interesting point you make, because Python is
         | actually one of the few languages that tried to break away from
         | its past (the whole 2.7 to 3.7 fiasco), but it seems the need
         | for a language to be stable is just much, much greater - so
         | features are just piled onto the existing standard instead.
         | 
         | If COBOL taught me one thing, it's that I'm pretty sure in 60
         | years time there will still be critical infrastructure running
         | on Python 2.7.
        
           | neysofu wrote:
           | That quote is seriously overused, to the point where valid
           | criticisms will be met with disapproval simply because the
           | language falls under condition (1).
        
         | cjauvin wrote:
         | I understand your feeling and I would tend to agree for things
         | in other domains.. but for a programming language, I find that
         | if:
         | 
         | (1) It doesn't make the language less efficient
         | 
         | (2) The new feature is coherent with the rest of the language
         | 
         | (3) It doesn't make learning the language harder
         | 
         | (4) It brings joy in my life (as f-strings do)
         | 
         | Then.. it's ok :-)
        
           | rement wrote:
           | I have never seen f-strings! It's my lucky day!
           | https://xkcd.com/1053/
           | 
           | Time to refactor the project I am currently working on that
           | is loaded with `str.format()`
        
             | ZephyrBlu wrote:
             | f-strings are truly amazing. They're very painless. The
             | only gotcha I've run into is accessing a dict from inside
             | one. You need to watch out for you quotations :).
        
           | chriswarbo wrote:
           | There are some 'invisible' downsides to adding new features,
           | which often get overlooked:
           | 
           | - Tooling, code analysers, etc. have to be updated to
           | understand the new features. Tools which are dead or
           | "finished" may stop working.
           | 
           | - The _possibility_ that someone _might_ use a new feature
           | can break guarantees that are relied upon by existing code.
           | An obvious example would be adding try /catch to a language:
           | in languages without this, a function call is guaranteed to
           | either return control to us, or to run indefinitely.
           | Libraries might rely on this to clean up file descriptors,
           | etc. afterwards. Such libraries would be broken by the mere
           | _existence_ of try /catch; even if we never actually use it.
           | 
           | That said, I'm a big fan of pattern-matching, so it would be
           | nice to have in Python, rather than crude approximations like
           | '{pattern1: A, pattern2: B, pattern3: C, ...}[myVal]'
        
         | 0xbadcafebee wrote:
         | If developers actually knew what simplicity was they'd stop
         | worshipping it.
         | 
         | Brainfuck is an extremely simple language. I mean, it's
         | perfect. Only 8 instructions! Only 1 pointer! Turing complete!
         | Why isn't everyone writing their code in this language?
         | 
         | A bicycle attached to a wheelbarrow is extremely simple
         | transportation. You can get anywhere you need to go, you can
         | carry heavy loads, it's easy to use, easy to fix, cheap. Why
         | would you use anything else?
         | 
         | Wood is a great building material. You can build a building
         | several stories tall, it's cheap, plentiful, easy to work with.
         | We should just standardize all construction on wood.
         | 
         | Water is the simplest beverage. It's clean, healthy, easy to
         | ship, easy to store. We don't need to drink anything else.
        
         | whalesalad wrote:
         | String formatting with f"" has been the new sheriff in town for
         | a while and it is really killer.
        
           | pletnes wrote:
           | Yes, and it also takes approx 11 seconds to learn, since
           | str.format already had exactly the same syntax, just slightly
           | more verbose.
        
             | leadingthenet wrote:
             | I never understood why they didn't remove the previous
             | ones.
             | 
             | Isn't there supposed to be only one obvious way of doing
             | these things?
        
               | elisaado wrote:
               | You can't just remove things, that'd break stuff!
        
               | leadingthenet wrote:
               | This is why the language is getting bloated. People
               | shouldn't be so obstinately against breaking changes.
        
               | spockz wrote:
               | That is why scala has scalafix[1] where library
               | maintainers can provide rules along with newer versions
               | of libraries that can be used to automatically, either at
               | build time or out of band on the source, translate old
               | constructs/patterns in the new.
               | 
               | See it as deferred refactoring for library maintainers.
               | Library maintainers that work in a monorepo with their
               | users get this refactoring feature for free.
               | 
               | [1]: https://scalacenter.github.io/scalafix
        
               | linkdd wrote:
               | greeting = "hello {}"       greet = partial(str.format,
               | greeting)       greet("world")
               | 
               | How would you pass a variable format string to f"" ?
        
               | nokko wrote:
               | I mean, if you're comfortable with `functools.partial`,
               | lambdas are no great stretch:
               | greet_fstring = partial(lambda _,s: f"hello {s}",
               | greeting)
        
               | eljost wrote:
               | You can use variables in the formats.                 >>>
               | flt = 1.2345       >>> two = 2       >>> f"{flt:.{two}f}"
               | '1.23'
        
               | thaumasiotes wrote:
               | That is the opposite of the problem being posed. The
               | question is how you define `greet` using f-strings.
        
               | sumzup wrote:
               | greet = lambda x: f"hello {x}"
        
               | thaumasiotes wrote:
               | Why is the example                 greet =
               | partial(str.format, greeting)       greet("world")
               | 
               | as opposed to just
               | greeting.format("world")          ?
        
               | sumzup wrote:
               | greet = lambda x: f"hello {x}"
        
               | pletnes wrote:
               | Or read the string to be formatted from a file, to name
               | another use case.
        
               | notatoad wrote:
               | Python already broke backwards compatibility once. It
               | didn't got over well
        
           | agumonkey wrote:
           | I believe it's been a cause of care for very easy and
           | expressive string formatting syntax in other languages
        
         | roelschroeven wrote:
         | And probably other situations, like perhaps corporate
         | environments, where you're not supposed to use the new more
         | advanced parts because not everyone on the team knows them.
         | Python is evolving into several different languages. "There
         | should be one-- and preferably only one --obvious way to do
         | it." Yeah right. I'm waiting for a PEP that deprecates PEP 20,
         | "The Zen of Python". It's become more and more clear that the
         | core developers don't follow it all anymore.
        
           | mrfusion wrote:
           | I thought I'd learn Perl once so I started reading a book on
           | it. I was shocked that literally the bottom half of every
           | page was footnotes. I gave up after a few pages.
           | 
           | Too much mental overhead. Other people love that kind of
           | stuff though.
        
             | ghshephard wrote:
             | I was a Perl developer/scripter for the better part of 3
             | years - wrote a 2-way LDAP<-> HRIS synchronization system
             | in it, complete with customizeable Schemas. Then, 3 or so
             | years into my Perl experience, in which I still needed to
             | look at template code every time I did a
             | HashOfArray/ArrayOfHash, I tripped across some python code
             | explaining how everything was objects.
             | 
             | Within a few seconds I tested that theory, by populating a
             | list with dicts and voila - just worked. Close to the last
             | day I ever touched Perl.
             | 
             | The python language expansions that have come recently,
             | f-strings, walrus operator, and now matching - are great in
             | that they _don 't make the language more complex_ - all
             | three of these are easily explainable in a few minutes to
             | the novice, and once they understand it, they can quickly
             | (and profitably) incorporate it into their code.
             | 
             | I _wan 't_ there to be a steady drumbeat of these
             | improvements that let me write more elegant code, more
             | concisely.
             | 
             | Try and find a _single_ python developer who would give up
             | their f-strings now.
        
               | adamc wrote:
               | Yeah, this. I love Python, and I hated Perl. Even Java
               | was a pleasure compared to Perl.
               | 
               | At one time, a trainer was trying to tell us Ruby was the
               | new hotness (2009 or 2010, I think). I liked Ruby OK, but
               | Python seems cleaner and we stuck with it. I have not
               | felt the slightest regret.
        
             | 0xbadcafebee wrote:
             | This is the first time in the history of the internet that
             | anyone has complained about too much documentation.
        
             | adamc wrote:
             | I programmed in Perl 5 for several years. Ugh. That
             | language was hard to read, and some of the features (list
             | vs. scalar context, for example) were awful. I have never
             | wanted to write another Perl program. Capable, but painful
             | to maintain.
        
           | make3 wrote:
           | I think this comment is super exaggerated. In my experience
           | pretty much all features in Python 3 by far are really
           | welcome. The only features you're usually not supposed to use
           | are very obvious ones, inspect, metaclasses and nested
           | comprehensions, which are super uncommon and feel like dark
           | magic that you would obviously not want to use, or just shit
           | ugly code in the case of nested comprehensions.
        
             | cjohnson318 wrote:
             | Yes, I think the general consensus on metaclasses is that
             | if you don't already know what they are, then you probably
             | don't need to use them. There's some metaclasses in Django,
             | but it's pretty easy to see how you're expected to use them
             | from examples, and you don't need to _really_ understand
             | what 's going on.
        
             | enriquto wrote:
             | What's the problem with nested comprehensions? How else do
             | you create bi-dimensional stuff?
        
             | pmart123 wrote:
             | I agree with this up through Python 3.7. The recent updates
             | though seem to be unnecessary or have obtuse syntax.
        
         | pizza wrote:
         | This feature could make a lot of code that people write quite
         | often a fair amount simpler, though. I'm looking forward to
         | this feature quite a bit.
        
         | adamc wrote:
         | I don't really agree. I helped steer my organization to Python
         | more than a decade ago -- its mix of capability and readability
         | made it a great fit, and it remains so. Nothing I saw in this
         | made me worried that people would struggle to read it.
         | F-strings are great, a huge improvement on needing to say
         | .format() all the time, and format was an improvement on the
         | original use of % (more descriptive).
         | 
         | C++ is a wholly different beast. Template metaprogramming
         | achieves great things, but at significant cost to readability.
        
         | cjohnson318 wrote:
         | I think str.format() was an improvement on from % formatting,
         | and that the f strings are an improvement on str.format(). It's
         | readable, concise, and it's familiar from other scripting
         | languages.
         | 
         | I think the advantage of switch statments and pattern matching
         | is that you know the scope of the thing you're switching or
         | matching on, but you don't have that restriction in
         | if/elif/else blocks. There's nothing keeping me from adding a
         | condition like, `elif day == "Tuesday":`, that has nothing to
         | do with the task at hand. When I see switch or match, I feel
         | like I know what I'm getting into.
        
         | asah wrote:
         | sorry for the downvote: please propose solutions that allow the
         | language to evolve and not stagnate.
         | 
         | example: pylint-type tools that flag old ways of doing things,
         | and suggest replacement syntax (e.g.
         | https://pycodequ.al/docs/pylint-messages/r1717-consider-usin...
         | )
        
       | sireat wrote:
       | So the same idea as pattern matching in Scala?
       | 
       | If it can be used as switch case on steroids then I am all for
       | it.
       | 
       | Why Python never got switch case is an interesting question.
        
       | naebother wrote:
       | Maybe this will grow on me, but at first glance this looks
       | needlessly complex. I don't think I've even fully comprehended
       | the syntax after staring at for a few minutes:
       | https://www.python.org/dev/peps/pep-0634/#appendix-a-full-gr...
        
       | theptip wrote:
       | Does anyone have a usecase where they think this new syntax
       | shines? I'm not really seeing anywhere in my projects that I'd
       | use this, but it seems to be well-loved in Elixir?
        
         | iso8859-1 wrote:
         | They have a dedicated PEP for motivation:
         | https://www.python.org/dev/peps/pep-0635/
        
       | ur-whale wrote:
       | And here I was thinking python was _finally_ adding built-in,
       | native, regex matching to the language, the _one last_ reason I
       | still use perl sometimes because of the quasi java-level
       | verbosity and heavy-handedness of the re python package.
       | 
       | But no, it's just about adding switch to python ... frankly, who
       | cares.
        
         | atoav wrote:
         | What do you mean with built-in native? Isn't `import re` kinda
         | built-in? It is not an external dependency. So you could even
         | run something like this from the terminal and get 1234 replaced
         | by 2021:
         | 
         | echo "1234foo" | python3 -c 'import re, sys;
         | t=sys.stdin.read(); print(re.sub(r"(\d{4})", "2021", t))'
        
           | SrslyJosh wrote:
           | I believe they mean adding a literal syntax specifically for
           | regular expressions, ala perl and ruby, so you could write
           | something like:
           | 
           | print(/\d{4}/.sub("2021"))
           | 
           | The backslash makes that example a little ugly, but maybe a
           | delimiter other than "/" would work better. It's too bad that
           | r"" is already taken for raw strings.
        
             | nerdponx wrote:
             | Could be x"" for _regeX_ or p "" for _Pattern_
        
           | ur-whale wrote:
           | In perl:
           | 
           | print($1) if(/^hello (w[^d]+d)/);
           | 
           | Do the same in python and pipe the code to wc -c
           | 
           | Oh, and note the absence of any "import" statement or quotes
           | in the perl code.
           | 
           | Python is not has heavy-handed as C++ for regex parsing, but
           | not by much.
        
       | kasperni wrote:
       | Java is also in proces of adding Pattern Matching over the next
       | couple of releases [1].
       | 
       | [1] https://www.infoq.com/articles/java-pattern-matching/
        
       | bjourne wrote:
       | Pretty cute syntax, but not what I'd wanted. It takes something
       | that is already trivial to write and makes it simpler. Not a lot
       | of "bang for your syntax bucks" so to speak. E.g the interpreter
       | example from the PEP could have been written:
       | parts = command.split()         if not (0 < len(parts) < 3):
       | raise TypeError(...)         cmd, arg = parts         if cmd ==
       | 'quit':             ...         elif cmd == 'get':
       | character.get(arg, current_room)         elif ...:
       | ...
       | 
       | For more advanced examples, you'd use dictionary dispatch anyway.
       | Will this syntax work with numpy?
        
         | breuleux wrote:
         | Your code is buggy, though. It will only ever accept two parts
         | because of `cmd, arg = parts`, so `["quit"]` will fail, and
         | each command might accept a different number of parts, so you
         | can't just test `0 < len(parts) < 3` for all of them. The
         | pattern matching version is harder to get wrong.
        
       | bob1029 wrote:
       | I just took a look at this and I am confused as to the actual
       | practical utility of pattern matching in a language that is not
       | strongly-typed to begin with.
       | 
       | My initial take upon stumbling upon the controversy was "why
       | would pattern matching be bad?" because I have only experienced
       | it through the lens of C# 9.0. Upon reviewing PEP 622 and looking
       | at some examples of usage... I am in agreement with the
       | detractors. This just doesn't seem to make sense for python, but
       | I would certainly hate to get in the way of someone's particular
       | use case as long as the new feature doesn't fundamentally cripple
       | the language for others.
       | 
       | IMO, Microsoft nailed it with their pattern matching
       | implementation:
       | 
       | https://docs.microsoft.com/en-us/dotnet/csharp/pattern-match...
        
         | frou_dh wrote:
         | Python is strongly-typed. With its built-in type annotation
         | syntax and a checker like mypy or pyright, it is statically-
         | typed, too.
        
       | pansa2 wrote:
       | > _The Python steering council has, after some discussion,
       | accepted the controversial proposal to add a pattern-matching
       | primitive to the language._
       | 
       |  _Controversial_ is correct. A poll showed a majority (65%) of
       | core developers opposed to this particular proposal, and a
       | plurality (44%) opposed to pattern matching altogether.
       | 
       | https://discuss.python.org/t/gauging-sentiment-on-pattern-ma...
        
         | thomasahle wrote:
         | Maybe adding new syntax should require a 2/3 majority or more.
        
         | adamdusty wrote:
         | > 34 voters
        
           | pansa2 wrote:
           | Is that not a reasonable sample of the 87 core developers
           | eligible to vote?
           | 
           | https://discuss.python.org/groups/committers
        
         | magnusmundus wrote:
         | It's controversial, granted, but I don't think that's a fair
         | reading of the poll. Here's another:
         | 
         | * A majority (56%) of responders want some form of pattern
         | matching.
         | 
         | * Exactly half of all responders, forming nearly 90% of the
         | above majority, are fine with that form being PEP 634.
         | 
         | * There are differing opinions about supporting PEPs, but a
         | supermajority (70%) of those who agree with PEP 634 are fine
         | with it alone.
         | 
         | The fact that it was possible to express more nuance when
         | agreeing with PEP 634 shouldn't diminish their voice against
         | those who reject the idea altogether.
        
           | pansa2 wrote:
           | > _Exactly half of all responders, forming nearly 90% of the
           | above majority, are fine with that form being PEP 634._
           | 
           | That half includes those who voted for "accept 634 + 640" or
           | "accept 634 + 642", whom I doubt are entirely happy with the
           | decision to accept PEP 634 _and reject 640 & 642_.
        
             | magnusmundus wrote:
             | My point was that you cannot claim "65% of responders
             | opposed this particular proposal". I understand, they're
             | possibly not entirely happy. The poll is flawed that way:
             | "accept 634" should not mean "reject 640 & 642".
             | 
             | That said, I interpret this part:
             | 
             | > PEP 642's proposed syntax does not seem like the right
             | way to solve the jagged edges in PEP 634's syntax
             | 
             | to mean that this is merely an initial spec. Those unhappy
             | with the syntax can avoid using it for now, there are no
             | breaking changes. It took a couple iterations to refine the
             | async syntax too, remember, and (IMHO) we arrived at a
             | clean-enough version of it. I have hope!
        
       | zepatrik wrote:
       | The comments on LWN are just hilarious.
       | 
       | > I'm going to submit a PEP to add a kitchen sink to Python.
       | 
       | I personally would opt for the sink with the snake, as it is more
       | Pythonic, despite not being the nicest and cleanest solution (is
       | that a Pythonic property as well?).
        
         | erichurkman wrote:
         | Mozilla for a time had a kitchen sink
         | (https://bugzilla.mozilla.org/show_bug.cgi?id=122411) at
         | about:kitchensink.
         | 
         | It looked like this: https://www-archive.mozilla.org/docs/web-
         | developer/samples/k...
        
       | VectorLock wrote:
       | Interesting discussions over on Twitter about the new parser
       | might be letting out the complexity genie and how some think that
       | might not be the greatest.
       | https://twitter.com/ramalhoorg/status/1358168753100496907
        
         | stickyricky wrote:
         | Not really. Its a string of preferences for Python's
         | development. I hope the author pursues those endeavors and
         | encourages others to join him. But they're not an argument
         | against pattern matching.
        
           | VectorLock wrote:
           | Talking about preferences still qualifies as interesting
           | discussion.
        
         | paulgb wrote:
         | As someone who hasn't been following closely, was the PEG
         | parser necessary for pattern matching or is that an unrelated
         | change?
        
           | pansa2 wrote:
           | IIRC one of Guido's reasons for switching to a PEG parser was
           | to enable the addition of pattern matching.
        
             | erichurkman wrote:
             | And it allowed some non-intuitive parser limitations to be
             | lifted, like full expressions in decorators
             | (@buttons[0].click) and parentheses in context expressions
             | (https://bugs.python.org/issue12782).
        
       ___________________________________________________________________
       (page generated 2021-02-09 23:00 UTC)