Hi Brandt,

On 30/03/2021 11:49 pm, Brandt Bucher wrote:
Hi Mark.

I've spoken with Guido, and we are willing to propose the following amendments 
to PEP 634:

- Require `__match_args__` to be a tuple.

I think we're all in agreement on this one.
Let's just do it.

- Add new `__match_seq__` and `__match_map__` special attributes, corresponding 
to new public `Py_TPFLAGS_MATCH_SEQ` and `Py_TPFLAGS_MATCH_MAP` flags for use 
in `tp_flags`. When Python classes are defined with one or both of these 
attributes set to a boolean value, `type.__new__` will update the flags on the 
type to reflect the change (using a similar mechanism as `__slots__` 
definitions). They will be inherited otherwise. For convenience, 
`collections.abc.Sequence` will define `__match_seq__ = True`, and 
`collections.abc.Mapping` will define `__match_map__ = True`.

Using this in Python would look like:

```
class MySeq:
     __match_seq__ = True
     ...

class MyMap:
     __match_map__ = True
     ...
```

I don't like the way this need special inheritance rules, where inheriting one attribute mutates the value of another.
It seems convoluted.

Consider:

class WhatIsIt(MySeq, MyMap):
    pass

With __match_container__ it works as expected with no special inheritance rules.

This was why you convinced me to split __match_kind__; it works better with inheritance.

Anther reason for preferring __match_container__ is that it provides a better option for extensibility, IMO. Suppose we wanted to add a "set" pattern in the future, with __match_container__ we just need to add a new constant.
With your proposed approach, we would need another special attribute.


Using this in C would look like:

```
PyTypeObject PyMySeq_Type = {
     ...
     .tp_flags = Py_TPFLAGS_MATCH_SEQ | ...,
     ...
}

PyTypeObject PyMyMap_Type = {
     ...
     .tp_flags = Py_TPFLAGS_MATCH_MAP | ...,
     ...
}
```

I'm wary of using up tp_flags, as they are a precious resource, but this does provide a more declarative way to specific the behavior than setting the attribute via the C-API.


We believe that these changes will result in the best possible outcome:
- The new mechanism should faster than either PEP.

The naive implementation of the boolean version might be a tiny bit faster (it would hard to measure a difference). However, once specialized by type version (as we do for LOAD_ATTR) both forms become a no-op.

- The new mechanism should provide a better user experience than either PEP 
when defining types in either Python *or C*.

The inheritance rules make __match_container__ a better user experience in Python, IMO. As for C, there no reason why the it would make any difference, __match_container__ could be
(tp_flags & (Py_TPFLAGS_MATCH_SEQ|Py_TPFLAGS_MATCH_MAP))
shifted to line up the bits.


If these amendments were made, would you be comfortable withdrawing PEP 653? We 
think that if we're in agreement here, a compromise incorporating these 
promising changes into the current design would be preferable to submitting yet 
another large pattern matching PEP for a very busy SC to review and pronounce 
before the feature freeze. I am also willing, able, and eager to implement 
these changes promptly (perhaps even before the next alpha) if so.

I think we are close to agreement on the mechanism for selecting which pattern to match, but I still want the better defined semantics of PEP 653.


Thanks for pushing us to make this better.

And thank you for the feedback.

Cheers,
Mark.
_______________________________________________
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/VXSUTM6CNEMOBZUJZXVP42OYYZWCBE2C/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to