On Sat, Oct 31, 2020 at 6:30 PM Nick Coghlan email@example.com wrote:
On Sat., 31 Oct. 2020, 9:29 pm Steven D'Aprano, firstname.lastname@example.org wrote:
(3) Overriding the default comparison with an explicit sigil is allowed:
case ==True: print("True, or 1, or 1.0, or 1+0j, etc") case ==None: print("None, or something weird that equals None") case is 1943.63: print("if you see this, the interpreter is caching floats")
Where is this override allowed? [...]
You're quoting from Steven's counter-proposal, which he prefaced with:
So here's a counter suggestion:
If PEP 634 allowed the exact comparison operator to be specified for patterns (with at least "==" and "is" allowed), and patterns with such explicit operators allowed arbitrary primary expressions as PEP 642 proposes, that would indeed address the bulk of my concerns:
- literal patterns would be an unambiguous shorthand for a comparison
pattern (always equality - see discussion below)
- attribute patterns would be an unambiguous shorthand for a comparison
pattern (always equality)
- the implementation would have no need to reinvent a subset of expression
compilation specifically for literal and attribute patterns, it could just use the parser to control the conversion of the restricted syntactic shorthand to the more general comparison pattern at the AST level
- the deferred ideas in PEP 642 (negated comparisons, containment checks)
would all be just as applicable as deferred ideas for an updated PEP 634 that included comparison patterns (with the question mark free spellings "!=", "is not", "in" and "not in")
(To a first approximation, the code needed to implement this feature for PEP 634 is the code I already wrote to implement "?" and "?is" for PEP 642, and the code deletion notes in my branch would also generally apply)
I think this over-stresses the notion that users might want to override the comparison operator to be used. We only have two operators that make sense in this context, 'is' and '==', and really, for almost everything you want to do, '==' is the appropriate operator. (There is a small trickle of bugs caused by people inappropriately using e.g. `if x is 1` instead of `if x == 1`, suggesting that if anything, there is too much freedom here.) The big exception is `None`, where you basically always want to use `is`, which is what PEP 634 does.
In PEP 622, we didn't do this, and we felt uncomfortable about it, so we changed it in PEP 634.
We also changed it for True and False, because we realized that since 1 == 1.0 == True, people writing ``` case True: ``` would expect this to match only Booleans. The main use case here is situations (like JSON) where Booleans are *not* to be considered equivalent to 0 and 1, which using PEP 622 would have to be written as ``` case bool(True): ``` which is hard to discover and not that easy to grasp when reading either.
There's not really ever a reason to write ``` case ==True: # Using Steven's notation ``` since that's just an odd and misleading way to write ``` case 1: ```
I don't ever want to be having conversations about why "case True:" doesn't
behave the same way as "case some.attr.referring.to.true:".
And you won't, because why would people define their own names for True and False? For sure people will define constants with Boolean values (e.g. `DEBUG = True`) but these aren't good candidates for use in patterns. I could imagine seeing ``` match DEBUG_NETWORK, DEBUG_LOGIC: case False, False: pass case False, True: print("We're debugging logic only") case True, False: print("Debugging network only") case True, True: print("Debugging network and logging") ``` but I would be surprised by ``` match x: case DEBUG: ... ``` just like I'd be surprised seeing ``` if x == DEBUG: ... ```
PS. Using `...` as a literal pattern is also Steven's invention, this isn't in PEP 634. People would probably think it had some special meaning as a pattern rather than understanding it was meant as the literal value `Ellipsis`.