Thanks for taking the time to work on this, Mark.

Overall, I'm skeptical of this proposal. It seems like it takes a lot of 
"simple" things and makes them quite complex, and takes many "static" things 
and makes them quite dynamic. I feel that it also misrepresents certain aspects 
of PEP 634.

Here's a more detailed commentary:

> Pattern matching will be more usable for complex classes, by allowing classes 
> more control over which patterns they match.

I fear this is at the expense of most simple classes, which currently "just 
work" with PEP 634. I'm not convinced that making it easier for very 
complicated classes (like those in `sympy`) to participate at the expense of 
everyday classes is a win.

For comparison, here is what (as I understand it) each PEP requires for a class 
to be used in a pattern such as `C(x, y, z)`:

```py
class C:
    """A PEP 634 matchable class."""
    __match_args__ = ...

class C:
    """A PEP 653 matchable class."""
    __match_kind__ = MATCH_CLASS
    __attributes__ = ...
    def __deconstruct__(self):
        ...
```

For a pattern with no positional subpatterns, such as like `C()` or `C(x=x, 
y=y, z=z)`:

```py
class C:
    """A PEP 634 matchable class (all classes work)."""

class C:
    """A PEP 653 matchable class."""
    __match_kind__ = MATCH_CLASS
    __attributes__ = ...
    def __deconstruct__(self):
        ...
```

It also appears that we lose a lot of expressive "idioms" by requiring 
`__attributes__` to be complete. For example, the following attribute 
extractions work with PEP 634, but not PEP 653.

```py
match subject:
    case object(a=_):
        # Match any object with an "a" attribute.
        ...
    case object(x=x, y=y, z=z):
        # Match any object with "x", "y", and "z" attributes, extracting them.
        ...
```

This also means that matching classes like `types.SimpleNamespace` are much 
less powerful under PEP 653, since the class must know which attributes are 
"allowed" to be looked up.

Further, this whole specification shifts most of the matching logic from the 
class in the pattern to the subject itself:

```py
match ChildA(), ChildB():
    case Parent(a, b), Parent(x, y):
        ...
```

The above pattern could have completely different rules for extracting `a` and 
`b` vs `x` and `y` if either child overrides `__deconstruct__`.  I think that 
is a mistake.

> PEP 634 also privileges some builtin classes with a special form of matching, 
> the "self" match. For example the pattern `list(x)` matches a list and 
> assigns the list to `x`. By allowing classes to choose which kinds of pattern 
> they match, other classes can use this form as well.

This is already fairly trivial to implement:

```py
class C:
    __match_args__ = ("_self",)
    _self = property(lambda s: s)
```

You can even avoid adding a `_self` attribute if you do some magic with 
descriptors... ;). We could consider provide a decorator for this somewhere in 
the stdlib if there's demonstrated need (but I'm not sure there will be).

> All classes should ensure that the the value of `__match_kind__` follows the 
> specification. Therefore, implementations can assume, without checking, that 
> all the following are false:
> `(__match_kind__ & (MATCH_SEQUENCE | MATCH_MAPPING)) == (MATCH_SEQUENCE | 
> MATCH_MAPPING)`
> `(__match_kind__ & (MATCH_SELF | MATCH_CLASS)) == (MATCH_SELF | MATCH_CLASS)`
> `(__match_kind__ & (MATCH_SELF | MATCH_DEFAULT)) == (MATCH_SELF | 
> MATCH_DEFAULT)`
> `(__match_kind__ & (MATCH_DEFAULT | MATCH_CLASS)) == (MATCH_DEFAULT | 
> MATCH_CLASS)`

Oof. I was scratching my head for way too long at this before I noticed the 
previous sentence said "false". Maybe reword this section to indicate the 
conditions that hold *true*? :)

> Security Implications
> Preventing the possible registering or unregistering of classes as sequences 
> or a mappings, that PEP 634 allows, should improve security. However, the 
> advantage is slight and is not a motivation for this PEP.

I would say the advantage is nonexistent. How is this any different than 
tweaking the flags in a class's `__match_kind__`?

> Efficient Implementation / Implementation

I won't get too deep into this section, but on the surface most flavors of 
implementation/optimization present here are also possible with PEP 634. I 
understand that you feel there are benefits to having "rules" for what 
optimizations are legal, but we don't need to completely change the mechanics 
of the match statement in order to do so.

> Because the object model is a core part of Python, implementations already 
> handle special attribute lookup efficiently. Looking up a special attribute 
> is much faster than performing a subclass test on an abstract base class.

But calling a `__deconstruct__` method whenever positional arguments are 
present will slow down normal class matches, right? I see it as mostly a wash.

> The changes to the semantics can be summarized as:
> - Selecting the kind of pattern uses `cls.__match_kind__` instead of 
> `issubclass(cls, collections.abc.Mapping)` and `issubclass(cls, 
> collections.abc.Sequence)` and allows classes control over which kinds of 
> pattern they match.
> - Class matching is via the `__attributes__` attribute and `__deconstruct__` 
> method, rather than the `__match_args__` method, and allows classes more 
> control over how they are deconstructed.

In general, it seems to me that this proposal prioritizes:

- complicated library code
- ease of implementation in the interpreter

over:

- simple client code
- general usability

I can't say I support that, generally. When working on PEP 634, we tossed lot 
of more complicated, powerful protocols (like `__match__` and several others 
before it... don't mention the phrase "match proxy" around any of the authors!) 
in favor of simplicity. This sort of feels like a rehash of that.

Brandt
_______________________________________________
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/ZXKAKV62YPKP5JYOV7EFY62MGCAW2BZ3/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to