On Sat., 31 Oct. 2020, 9:29 pm Steven D'Aprano, <st...@pearwood.info> 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? It isn't covered under the syntax for value
patterns or literal patterns:

* https://www.python.org/dev/peps/pep-0634/#value-patterns
* https://www.python.org/dev/peps/pep-0634/#literal-patterns

and there aren't any other pattern types that make comparisons.

It also isn't in the draft reference implementation.

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 don't think that there will be any ambiguity between the unary "=="
> pattern modifier and the real `==` operator. But if I am wrong, then we
> can change the spelling:
>
>
>     case ?None:
>         print("None, or something weird that equals None")
>
>     case ?is 1943.63:
>         print("if you see this, the interpreter is caching floats")
>
>
> (I don't love the question mark here, but I don't hate it either.)
>
> The important thing here is that the cases with no sigil are the common
> operations; the sigil is only needed for the uncommon case.
>

The tokeniser does struggle with "==" appearing after "=" or ":" in class
patterns and mapping patterns, so you have to make sure to help it out with
whitespace or parentheses.

That's why I didn't use it for PEP 642, but the whitespace sensitivity
would be more tolerable if the explicit symbol was left out most of the
time.



>
> (4) Patterns which could conceivably be interpreted as assignment
> targets default to capture patterns, because that's what is normally
> wanted in pattern matching:
>
>
>     case [1, spam, eggs]:
>         # captures spam and eggs
>
>
> If you don't want to capture a named value, but just match on it,
> override it with an explicit `==` or `is`:
>
>
>     case [1, ==spam, eggs]:
>         # matches `spam` by equality, captures on eggs
>

As noted above, the current PEP 634 spec doesn't allow this, but if it did,
then I agree it would adress most of the concerns that prompted me to write
PEP 642.

If the 634 PEP authors are amenable, I'd be happy to prepare a PR against
the PEP that made this change so you could see what it would look like at
the grammar level.


>
> Quoting the PEP:
>
> "nobody litters their if-elif chains with x is True or x is False
> expressions, they write x and not x, both of which compare by value, not
> identity."
>
> That's incorrect. `if x` doesn't *compare* at all, not by value and not
> with equality, it duck-types truthiness:
>

Aye, I considered going back and rewording that part to be more technically
precise, but never actually did it (whether by type coercion or equality
comparison, the ultimate effect is being more permissive than the strict
identity check suggested for literal patterns).

```
> >>> class Demo:
> ...     def __bool__(self):
> ...             return True
> ...     def __eq__(self, other):
> ...             return False
> ...
> >>> x = Demo()
> >>> x == True
> False
> >>> if x: print("truthy")
> ...
> truthy
> ```
>
> There's a reasonable argument to make that (unless overridden by an
> explicit sigil) the `True` and `False` patterns should match by
> truthiness, not equality or identity, but I'm not going to make that
> argument.
>

While I'd consider duck typing True & False less objectionable than
comparing them by identity (as it would follow PEP 8), it wouldn't fix the
key problem with special casing literals in the compiler: you lose that
special casing if the literal value is replaced by a symbolic reference to
the literal value.

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:".

If PEP 634 had comparison patterns, then users would get "== True" by
default for both literal and attribute patterns, "is True" if they
explicitly asked for it, and regular boolean coercion if they combined a
capture pattern with a guard expression.

I do agree that None & Ellipsis are less of a concern (as almost no one
overrides equality to compare equal to those, so comparing by equality vs
identity gives the same answer), but that also means the special case would
serve little practical purpose.

>
Cheers,
Nick.



>
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/65IX6RIFYG6Z4DYVP5MJWSK6LKWOZ7VU/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to