News for hackers. Stuff that matters.
Re:Pattern matching accepted for Python by frou_dh on Tuesday February 09, 2021 @04:41PM (#26082703)
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.

Re:Pattern matching accepted for Python by brianberns on Tuesday February 09, 2021 @05:20PM (#26083177)
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.
Re:Pattern matching accepted for Python by thomasahle on Tuesday February 09, 2021 @05:38PM (#26083405)
Does it shadow the outside variable or mutate it?
Re:Pattern matching accepted for Python by pansa2 on Tuesday February 09, 2021 @05:43PM (#26083475)
Mutates it. Python `match` statements do not introduce a new scope.
Re:Pattern matching accepted for Python by lou1306 on Tuesday February 09, 2021 @06:17PM (#26083848)
Ouch, that's indeed pretty bad. I do expect `not_found = status` (that's how pattern matching works in several other languages), but it should be in its own scope, so that `not_found` is still `404` outside of the `match` block!
Re:Pattern matching accepted for Python by nemetroid on Tuesday February 09, 2021 @06:59PM (#26084211)
Python doesn't have block scope. This can lead to some surprising behaviour:

  x = -1
  for x in range(7):
      if x == 6:
          print(x, ': for x inside loop')
  print(x, ': x in outer')
This outputs:

  6 : for x inside loop
  6 : x in outer
For consistency, I think it makes sense for match to behave in a similar way.
Re:Pattern matching accepted for Python by mumblemumble on Tuesday February 09, 2021 @10:51PM (#26085557)
It would make even more sense for Python not to adopt language features that can't be made to behave consistently with the language's existing syntax and semantics without introducing horrendous footguns.

I've been programming in dialects of ML for much longer than Python, so I absolutely appreciate the attraction of this feature. But, the opinion I'm coming to as I think more about this is:

  1. I *love* pattern matching.
  2. But not in Python.
Re:Pattern matching accepted for Python by yawaramin on Tuesday February 09, 2021 @11:18PM (#26085704)
Exactly. At this point it feels like Python is LARPing at being an ML. Without even block scoping, this is just asking for trouble.
Re:Pattern matching accepted for Python by chriswarbo on Wednesday February 10, 2021 @12:03PM (#26091780)
To be fair, lots of languages have been moving closer to ML recently (and new languages tend to look more ML-like than in the past). That includes the adoption of pattern matching, but also things like value objects, first-class functions, sum types, named tuples, algebraic datatypes, type inference, etc.

I don't think that's a bad thing. I do think care should be taken when incorporating features from other languages, to see how it interacts with existing features, what the best form of that feature would be, and perhaps whether some different feature could achieve a similar goal.

(For the latter point, I find it unfortunate that languages which already contain 'try/catch' have been introducing 'yield' and 'async/await' as separate features; rather than generalising to 'shift/reset' and implementing all three as libraries)

Re:Pattern matching accepted for Python by pfalcon on Wednesday February 10, 2021 @05:17AM (#26087450)
Interested in block-level scoping in Python? Please post on the python-ideas mailing list. Thanks.
Re:Pattern matching accepted for Python by mumblemumble on Wednesday February 10, 2021 @09:14AM (#26089363)
No, not interested in block-level scoping in Python. Why on earth would I ask a programming language I rely on for getting important work done to introduce so massive a breaking change as changing its scoping style?

"I don't think feature X is a good fit for Python because it interacts poorly with existing Python features Y and Z" is not a tacit statement of support for changing features Y and Z. It's a statement that means exactly what it says.

Like I alluded to in my grandparent post, I use other languages that are not Python, and like their features, too. That does not necessarily mean I want all my favorite features from those pulled into Python. Nor do I want my favorite features from Python pulled into other languages.

The best analogy I can think of is a college friend once developed this sort of transitive theory of food that went, "If A tastes good with B, and B tastes good with C, then A must taste good with C." This resulted in a number of questionable concoctions, like serving cottage cheese on top of chocolate cake because they both taste good with strawberries.

Re:Pattern matching accepted for Python by yawaramin on Wednesday February 10, 2021 @09:02AM (#26089189)
Actually, the opposite. Call me an old crank but I feel like Python should stay Python and not try to (badly) tack on ideas from ML.
Re:Pattern matching accepted for Python by jnxx on Wednesday February 10, 2021 @03:08PM (#26094013)
For my part, as I maintain some complex academic research software, I would be much more interested in continuing support for Python 2, and more comprehensive numerical, math and vector libraries for Racket.
Re:Pattern matching accepted for Python by ziml77 on Wednesday February 10, 2021 @12:06AM (#26085907)
I haven't been programming in languages with pattern matching longer than Python and I still agree with you. Pattern matching is awesome, but it doesn't suit Python at all. I hope they reconsider adding it.
Re:Pattern matching accepted for Python by pfalcon on Wednesday February 10, 2021 @05:18AM (#26087454)
No, we'll rather fix issues people see with it.

Interested in block-level scoping in Python? Please post on the python-ideas mailing list. Thanks.

Re:Pattern matching accepted for Python by pfalcon on Wednesday February 10, 2021 @05:17AM (#26087445)
> It would make even more sense for Python not to adopt language features that can't be made to behave consistently with the language's existing syntax and semantics

Current match behavior is consistent with existing syntax and semantics.

And no, not adopting new features known to be generally useful across programming languages is not "better". Instead, better to continue elaborating the language even after the initial pattern matching support is added.

Interested in block-level scoping in Python? Please post on the python-ideas mailing list.

Re:Pattern matching accepted for Python by mumblemumble on Wednesday February 10, 2021 @09:06AM (#26089247)
Why did you chop the last four words off of that sentence you quoted? All it accomplishes is making it so that the response rebuts a statement that wasn't actually made.
Re:Pattern matching accepted for Python by CogitoCogito on Tuesday February 09, 2021 @07:34PM (#26084456)
I don't know if I even know what "being consistent" would mean given the example here:

https://news.ycombinator.com/item?id=26082225

We don't shadow variables when they are re-used in comprehensions for example:

    >>> i = 4
    >>> [i for i in range(10)]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> i
    4
Given they're already accepting the oddity of having "case 404:" and "case variable:" mean very different things, I think they should have just gone the whole way and _not_ mutated outside variables. There seems to be little consistent with this addition to the language.
Re:Pattern matching accepted for Python by nemetroid on Wednesday February 10, 2021 @05:08AM (#26087393)
> We don't shadow variables when they are re-used in comprehensions for example:

I think "for example" makes this sound more general than it is. List comprehensions are one of the rare few constructs that introduce a new scope. The match block is more syntactically similar to if/while/etc. blocks, and so it makes sense that it would follow similar scoping rules.

This is not to say that I agree with the design as a whole. I think they should have went with:

  case obj.some_value:
      ...
  case some_value:  # behaves the same way as the previous
      ...
  case _ as variable:
      ...
  case (variable := _):  # an alternative to the previous syntax
      ...
I.e. I think the complete situation is messy, but it's not the variable scoping rules' fault.
Re:Pattern matching accepted for Python by chriswarbo on Wednesday February 10, 2021 @12:27PM (#26092091)
> The match block is more syntactically similar to if/while/etc. blocks, and so it makes sense that it would follow similar scoping rules.

I would argue that a stack of 'case's are a 'lambda' (and in particular a single 'case x: ...' is equivalent), and hence they should have function scoping like 'lambda' does.

'match' is a distraction; it's just a function call written backwards, i.e. `match x: f` is equivalent to `f(x)` (in this case Python happens to require `f` to be implemented using the stack-of-'case's form, but that seems incidental; similar to how 'raise' and 'except' are a general form of control flow, despite Python requiring values to be wrapped in something descended from 'Exception')

Re:Pattern matching accepted for Python by CogitoCogito on Wednesday February 10, 2021 @10:53AM (#26090813)
> I think "for example" makes this sound more general than it is. List comprehensions are one of the rare few constructs that introduce a new scope.

The rarity of the construct doesn't matter honestly. Are you saying that list comprehensions should _not_ have introduced a new scope because it was unusual?

> The match block is more syntactically similar to if/while/etc. blocks, and so it makes sense that it would follow similar scoping rules.

Syntactically yes, but semantically it is very different and the semantics must be taken into account as well. The example given at the top of this thread (case 404: and case variable:) is enough to convince me that having variable scoping is a brain-dead obvious requirement.

> I think the complete situation is messy, but it's not the variable scoping rules' fault.

I agree with that statement. I think that improving the design/semantics would be more effective than just adding some more scoping rules in. In fact, I don't think this PEP should have been accepted in this current form at all. But given the current design, block-level scoping is appropriate. Given another design like maybe those you mention might not require that, but I think focusing on the fact that python doesn't have block-level scoping makes no sense. The python language before this PEP is not the same as the one after this PEP. The new one should have block-level scoping in this instance.

Re:Pattern matching accepted for Python by pfalcon on Wednesday February 10, 2021 @05:19AM (#26087457)
> I think they should have just gone the whole way and _not_ mutated outside variables. There seems to be little consistent with this addition to the language.

Interested in block-level scoping in Python? Please post on the python-ideas mailing list. Thanks.

Re:Pattern matching accepted for Python by pansa2 on Tuesday February 09, 2021 @06:31PM (#26083968)
In those other languages, if `not_found` is equal to 404 before the match block, how do you write a clause that only matches if `status` is 404?

Do you have to use the integer literal 404 instead of the named integer `not_found`?

Re:Pattern matching accepted for Python by heisenzombie on Wednesday February 10, 2021 @01:51AM (#26086297)
Elixir uses the “pin operator”

“Use the pin operator ^ when you want to pattern match against a variable’s existing value rather than rebinding the variable.”

    iex> not_found = 404
    404
    iex> ^not_found = 200
    ** (MatchError) no match of right hand side value: 200
https://elixir-lang.org/getting-started/pattern-matching.htm...
Re:Pattern matching accepted for Python by pfalcon on Wednesday February 10, 2021 @05:21AM (#26087471)
Exactly, Elixir is usually the only example given. So, how it makes sense to blame Python here is unclear. There's a proposal to add similar "sigils" to Python pattern matching, it just didn't make it yet.
Re:Pattern matching accepted for Python by yw3410 on Tuesday February 09, 2021 @06:51PM (#26084133)
Depends on the language, but a lot of them use guard clauses (so case ... if cond =>).
Re:Pattern matching accepted for Python by DougBTX on Tuesday February 09, 2021 @11:02PM (#26085612)
Re:Pattern matching accepted for Python by lou1306 on Wednesday February 10, 2021 @05:57AM (#26087670)
In OCaml and F# you can use `when`:

    match status with
    | n when n = not_found -> ...
Re:Pattern matching accepted for Python by wendyshu on Tuesday February 09, 2021 @08:55PM (#26084969)
Reassignment not mutation
Re:Pattern matching accepted for Python by pansa2 on Tuesday February 09, 2021 @08:58PM (#26084987)
Ah yes, you’re right.
Re:Pattern matching accepted for Python by hmry on Tuesday February 09, 2021 @05:24PM (#26083222)
I don't get it, isn't that exactly what it's doing here?
Re:Pattern matching accepted for Python by magnusmundus on Tuesday February 09, 2021 @05:33PM (#26083343)
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).

Re:Pattern matching accepted for Python by wendyshu on Tuesday February 09, 2021 @08:56PM (#26084974)
Reassigning not mutating
Re:Pattern matching accepted for Python by Dylan16807 on Wednesday February 10, 2021 @03:33AM (#26086800)
Reassigning to a variable is how you mutate a variable, isn't it?

The value being [im]mutable is a different topic entirely.

Re:Pattern matching accepted for Python by carapace on Wednesday February 10, 2021 @11:43AM (#26091485)
There aren't actually "variables" in Python in the sense of named values, instead there are namespaces where values are stored and looked up under string identifier keys. (Just to add spice, some values, namely function and class objects, do get their names embedded in them, but this is only used for debugging. They are stored in enclosing namespace dicts like other values.):

    >>> def f(): pass

    >>> g = f

    >>> g
    <function f at 0x000001B4A686E0D0>

    >>> locals()
    {'__annotations__': {},
    '__builtins__': <module 'builtins' (built-in)>,
    '__doc__': None,
    '__loader__': <class '_frozen_importlib.BuiltinImporter'>,
    '__name__': '__main__',
    '__package__': None,
    '__spec__': None,
    'f': <function f at 0x000001B4A686E0D0>,
    'g': <function f at 0x000001B4A686E0D0>}
Re:Pattern matching accepted for Python by Dylan16807 on Wednesday February 10, 2021 @02:04PM (#26093341)
Wait, what's your definition of variable?

Because what you're describing fits perfectly into what I would call a variable. There is a mapping from an identifier to a slot that can store a value (or reference), and that mapping is stored in a specific scope. I would call that mapping a variable.

I'm not sure exactly why you mentioned objects that have names embedded in them. Is that relevant to the definition you're using?

Re:Pattern matching accepted for Python by carapace on Wednesday February 10, 2021 @02:42PM (#26093713)
> Wait, what's your definition of variable?

With full formality, the definition of "variable" depends on context. In assembly language and C variables are names for storage locations in RAM, in Python they are name bindings in a dict data structure.

One distinction we could make is whether the names are compiled away or kept and used at runtime.

In any event, the important thing is to keep clear in one's mind the semantics of the language one is using. In Python you have values (objects of various types: ints, strings, tuples, lists, functions, classes, instances of classes, types, etc.) some of which are mutable and others are immutable, and you have namespaces: dicts that map strings to values. These namespaces have nothing to do with the location of the values in RAM.

So it doesn't really make sense in Python to speak of "mutate a variable", you can mutate (some) values, and rebind values to names (new or old).

> I'm not sure exactly why you mentioned objects that have names embedded in them. Is that relevant to the definition you're using?

Not really, it's just another little point that sometimes confuses some people when they are coming to grips with the idea that in Python values are not associated with names except by namespace bindings. There are some values (function and class objects) that do get associated with names.

Re:Pattern matching accepted for Python by Dylan16807 on Wednesday February 10, 2021 @03:30PM (#26094316)
I suppose, but it's very strange to say "Assigning to a variable is classified as mutating the variable in some languages but not others, even though the underlying mechanism works exactly the same way."

Shouldn't terms like this be cross-language?

Re:Pattern matching accepted for Python by carapace on Wednesday February 10, 2021 @09:05PM (#26097395)
The underlying mechanism doesn't work the same though, e.g. in C assigning to a variable "mutates" the contents of RAM, in Python it mutates the namespace dictionary (which of course also results in some RAM contents changing too, but through a relatively elaborate abstraction.)

> Shouldn't terms like this be cross-language?

Variables in C are different beasties than variables in Python, and variables in Prolog are different from both, and none of those are like variables in math. It's a source of confusion that we use the word "variable" for a host of similar concepts. The word "type" is similarly overloaded in CS. (See https://www.cs.kent.ac.uk/people/staff/srk21/research/papers... )

FWIW, I'm just explaining what wendyshu was on about above. :)

Re:Pattern matching accepted for Python by Dylan16807 on Thursday February 11, 2021 @01:10AM (#26098754)
That's not exactly how C works, but I wasn't going to use C as my primary example, I was going to use Rust. You have to write "let mut" to let a variable be reassigned/mutated, and variables in Rust are almost identical to ones in Python as far as being an abstract 'namespace' binding.
Re:Pattern matching accepted for Python by carapace on Thursday February 11, 2021 @10:18AM (#26102337)
> That's not exactly how C works

Sure, I elided a bajillion details, and who knows what the CPU is doing under the hood anyway? :)

I've never used rust (yet) so I can't really comment on that.

FWIW namespaces in Python aren't abstract, they exist as dicts at runtime. You can modify the dict you get back from locals() or globals() and change your "variables" in scope:

    >>> d = locals()
    >>> d['cats'] = 'meow'
    >>> cats
    'meow'
Re:Pattern matching accepted for Python by jnxx on Wednesday February 10, 2021 @05:49AM (#26087633)
Reading the discussion, I think the criticism is more motivated by the subtle but crucial differences to most functional programming languages.
Re:Pattern matching accepted for Python by frou_dh on Wednesday February 10, 2021 @06:15AM (#26087800)
I was thinking more about the common criticism that something like `case Point2d(x, y):` "looks like an instantiation" and hence an equality check.

I actually replied to the wrong comment after reading several that visually looked similar at the time, so apologise for causing confusion in this subthread.

Re:Pattern matching accepted for Python by pfalcon on Wednesday February 10, 2021 @05:14AM (#26087423)
> EDIT: The lack of block scoped variable thing does seem like a wart right enough.

This is not specific to "match" statement, but is a general issue in Python. And thus, needs to have a general solution, orthogonal to pattern matching. Are you interested? Please post to the python-ideas mailing list.