7 ms·
> You can combine several literals in a single pattern using | ("or"): `case 401|403|404:` So how do I do a bitwise-or operation within a pattern? I think giv
by pansa2 6y ago
> You can combine several literals in a single pattern using | ("or"): `case 401|403|404:`
So how do I do a bitwise-or operation within a pattern?
I think given issues like this and the commonly-cited NOT_FOUND example [0], it might have been better to only allow pattern matches on compound data and disallow its use with simple values. That’s where pattern matching is most useful, as in the article‘s second example (`match point`), plus it would make it more obvious that the behaviour of `match` is different from C’s `switch`.
[0] The following code unintuitively assigns the value of status_code to the variable NOT_FOUND:
NOT_FOUND = 404
match status_code:
case NOT_FOUND:
print("HTTP Not Found")
Edit: OK, it looks like you can’t do arithmetic/bitwise operations in a pattern at all, so there’s no direct clash between bitwise or and this use of `|`.
Therefore if you need to match against a calculated value, you can’t do the calculation inline. Instead you need to calculate the value outside the match and give it a name - but you can’t match against a named local variable either!
- ok123456 6y agoWith enum.Flag and guard statements?
- macintux 6y agoAs an Erlang fan, I can definitely see myself falling into the NOT_FOUND trap. I frequently miss immutable data when working in Python; in general I’m conflicted about languages that retrofit functional programming features, because immutability is such a huge benefit.
- tannhaeuser 6y agoAs a Prolog fan, I'm conflicted about languages that retrofit logic programming features (such as pattern matching) because term unification is such a huge benefit ;)
- tobmlt 6y agoAs a guy who built an interval arithmetic constraint programming system, based on minikanren, in python for his PhD, I agree, unification is pretty sweet!
- JNRowe 6y agoOi, you can't leave us hanging like that! I'd really love to read it if you have a link, even more so after the extra paragraph in your HN bio.
- ihumanable 6y agoFun fact: erlang was originally implemented in prolog, its since been rewritten in C. Many of the features in the language were inspired by prolog.
- ledauphin 6y agoi'm not sure "immutable data" is precise as a complaint here - this is akin to the difference between `const` and `let` in Javascript, which has nothing to do with immutability of the data and everything to do with the immutability of a name binding. I do wish we had better first-class immutable data in Python, but that wouldn't help with the NOT_FOUND = 404 match val: case NOT_FOUND: ... scenario that everyone is (rightly) fixated on, because integers themselves are already immutable.
- macintux 6y agoTrue, I tend to conflate immutable bindings with immutable data. With Erlang, all bindings are immutable, which makes pattern matching more powerful (although it can lead to unexpected crashes on occasion).
- tom_mellior 6y ago> scenario that everyone is (rightly) fixated on Your "rightly" obviously varies, but this scenario is the poster child for enums, and you can match on enum members. The featured article has an example.
- bondarchuk 6y agoYou can make any code unintuitive by naming the variables wrong. Consider: LAST_MATCHED_STATUS_CODE = 404 match status_code: case LAST_MATCHED_STATUS_CODE: print("HTTP Not Found")
- ma2rten 6y agoThat's still unintuitive or at least strange because uppercase generally indicates constants.
- pansa2 6y agoRenaming the variable doesn’t fix the code. It still prints “HTTP Not Found” for every value of `status_code`.
- bondarchuk 6y agoright.. D'oh I gather that the proposed solution is to use something like enums? Or not do this at all?
- masklinn 6y agoYes, or not import the constants from their module aka import foo not from foo import BAR, BAZ, QUX
- LukeB42 6y agoMy gut tells me the logical `or` here should use the word "or" like in the rest of the language. Neat syntax overall but it's not clear what it makes more succinct than the equivalent `elif` statements.
- alpaca128 6y agoAgreed regarding the "or" - rejecting consistency here just because other languages do it differently is weird. > it's not clear what it makes more succinct than the equivalent `elif` statements But pattern matching is shorter than if-else in many cases and can actually differentiate between structures which makes it very flexible. It's like switch-case should have been from the start imho. As an example, in Rust I often do comparisons between certain values by simply matching a tuple of them: match (foo, bar) { (x, x) => true, // foo == bar (Foo::VariantA(42), _) => unreachable!(), // has to be a bug (Foo::VariantA(a), _) => a < 0, _ => false, } This is of course a rather simple example, but I hope it still conveys what I like so much about this kind of feature. It doesn't do more than an if-else chain, but under the right circumstances it really shines. Just like list comprehensions don't add any new functionality, but the filtering and mapping features are often simply more expressive for what you want to do. Although I'm not sure what to think of Python's preference to put the condition and code in different lines; maybe that's optional, which could make it more succinct when the situation permits it.
- mjw1007 6y agoI was worried about that example, but the problem doesn't seem to be too bad, because the spec says: « A match statement may have at most one irrefutable case block, and it must be last. » So if I understand correctly the following will be an import-time error. NOT_FOUND = 404 I_AM_A_TEAPOT = 418 match status_code: case NOT_FOUND: print("HTTP Not Found") case I_AM_A_TEAPOT: print("HTTP I'm a teapot")
- pwdisswordfish6 6y agoAgreed. They should have required an extra token like ? to disambiguate bindings from evaluations. Not only would it avert this pitfall, it would also obviate the need to have a special identifier to discard a bound value; instead of writing _ to discard a binding, one would just write ? without a variable name. I fear a poor design like this is going to not only discourage people from using the feature at all, it is also going to poison the well and discourage people from using pattern matching in languages with a much more robust implementation. Which is a shame, because I actually like pattern matching. (Tinfoil-hat take: Maybe that’s the whole point, after all Guido doesn’t like functional programming.)
- r-zip 6y agoSince the names have to be dotted anyway, why not .var_name? I feel like this implementation is seriously half-baked.
- gshulegaard 6y agoI could be wrong, but this PEP feels to me like it only got accepted because Guido is stepping (or stepped) back from his BDFL role. It has noticeably more rough edges and less consistency than most feature adds I have seen in the past. This is pure personal speculation though.
- enragedcacti 6y agoGuido sponsored the PEP so I doubt him being BDFL would have stopped it.
- masklinn 6y ago> [0] The following code unintuitively assigns the value of status_code to the variable NOT_FOUND: This seems sensible and intuitive, `NOT_FOUND` is not different than `not_found` or `bob`. It follows the normal rules of Python bindings. I'm way more annoyed by the special case for dotted names.
- pansa2 6y agoThe problem is that `NOT_FOUND` behaves differently from the literal `404`, which breaks an important principle: “if you see an undocumented constant, you can always name it without changing the code’s meaning” [0]. [0] https://twitter.com/brandon_rhodes/status/1360226108399099909 https://twitter.com/brandon_rhodes/status/136022610839909990...
- masklinn 6y agoThat is true, but for Python never having had constants. So as soon as you name an undocumented constant, you run the risk that people will update it. So that's less a principle and more a guideline. And hey, if it finally gets explicit variable declarations in Python I'm 100% all for it. implicit locals, `global`, and `nonlocal` are awful, viva `let` and `const` or whatever. As to the content of the tweet > The Substitution Principle, learned in algebra? Python is not algebra, and already breaks algebraic reasoning to and through. Just consider that `a = a + b` and `a += b` are completely different operations with possibly (and actually, for some types) completely different effects.
- pansa2 6y ago> `a = a + b` and `a += b` are completely different operations Getting off-topic, but IMO that’s a major design flaw in the language. Some others agree, e.g. https://twitter.com/joepolitz/status/1304992696293978112 https://twitter.com/joepolitz/status/1304992696293978112
- masklinn 6y agoOh I completely agree it’s a major design flaw of the langage and I was dismayed the core devs used it again with the in-place dict update of 3.9. My point was that if you were teaching people that pull thon follows strict algebraic principles you were already setting them up for a rude series of surprises.
- bjoli 6y agoI don't think I have ever used a language where this is not the case. You match against a pattern, not against the result of an expression. It is not that confusing once you have grooked it.
- Blikkentrekker 6y agoIn some languages, however, data constructors live in a separate namespace from variables and in some they do not. In ML and Rust, mistyping a a data constructor's name produces a variable, and thus matches everything, whereas OCaml and Haskell require that constructors start with an uppercase name, and disallows variables to do so, so this cannot easily occur. But, since in Rust data constructors are typically qualified with a namespace except for some frequently used ones, this is not a problem in practice.
- steveklabnik 6y agoIt’ll also often produce one or more warnings in Rust, which can help.
- Blikkentrekker 6y agoIndeed. — that Rust warns against unused variables and has language facilities to suppress such warnings if ever they be so intended has no doubt caught many typos that other languages have not.
- dmart 6y ago> That’s where pattern matching is most useful, as in the article‘s second example (`match point`), plus it would make it more obvious that the behaviour of `match` is different from C’s `switch`. Meanwhile, the top post on /r/python for the last few days has been "Ladies and gentlemen - switch cases are coming!" This feature and its footgun syntax are going to be a disaster for the casual Python audience.
- deleted 6y ago[deleted]
- andolanra 6y agoIt's worth noting that a properly-configured linter will give you an unused variable warning here, since you've bound to NOT_FOUND but not used it for anything.
- macintux 6y agoThat assumes it isn’t used again later.
- tom_mellior 6y ago> Therefore if you need to match against a calculated value, you can’t do the calculation inline. Instead you need to calculate the value outside the match and give it a name - but you can’t match against a named local variable either! Can you do either of those in other popular languages with pattern matching? Presumably the reason for wanting pattern matching wasn't to invent something completely new, but to implement something similar to pattern matching in other languages. (I know that C-style switches allow you to write constant arithmetic expressions in case labels.)
- pansa2 6y ago> Can you do either of those in other popular languages with pattern matching? Ruby supports matching against a local variable by pinning the variable (using a ^ prefix).
- BerislavLopac 6y agoI am aware that this is just an example for the apparent case of bad design, but in this particular example I'm always advising developers against using plain integer for HTTP status code - http.HTTPStatus enum is a much better solution.