On Tue, Jun 23, 2020 at 5:08 PM Guido van Rossum <guido@python.org> wrote:
On Tue, Jun 23, 2020 at 12:11 PM Brett Cannon <brett@python.org> wrote:
I will say that trying to follow https://github.com/python/peps/blob/master/pep-0622.rst#runtime-specification was really hard. Any chance of getting some pseudo-code that shows how a match is performed? Otherwise all of that wording tries so hard to be a spec that I found it hard to follow in my head in how things function.

Sorry about that. This section was subject to heavy editing recently and lost clarity. I will try to make it better! Writing it as pseudo code will take a little time, but I will give it a try.

I leave the decision about pseudocode up to you if you think you can just find words to clarify that section.
For instance, "When __match_args__ is missing (as is the default) or None, a single positional sub-pattern is allowed to be passed to the call" is really misleading as it seems that a "sub-pattern" in this case is just going to be a constant like `[1, 2, 3]`. Otherwise how does `["<"|">"]` or `[1, 2, *_]` get represented as a "single positional sub-pattern" (if either of those examples is possible)? The use of the term "sub-pattern" feels misleading because while you may consider even constant patterns a "pattern", going that generic feels like any pattern should fit in that definition when in fact it seems to only be an object where a direct equality check is done.

It seems the way things work is basically:

1. `__match__(obj)` returns a proxy object to have Python match against; it is passed in the thing that `match` is running against, returning `None` if it know there's no chance a match will work
2. If `__match_args__` is present, then it is used to map positional arguments in the pattern to attributes on the proxy object
3. From there the `match` functionality does a bunch of comparisons against attributes on the proxy object to see if the match works

Is that right? That suggests all the work in implementing this for objects is coming up with a way to serialize an object to a proxy that makes pattern matching possible.

Yes, that's right, and the protocol was defined carefully so that the author of __match__ doesn't have to do any pattern matching -- all they have to do is produce an object that has the right attributes, and the interpreter does the rest. Note that it is __match__'s responsibility to check isinstance()! This is because __match__ may not want to use isinstance() but instead check for the presence of certain attributes -- IOW, the class pattern supports duck typing! (This was a little easter egg. :-)

Ah, so that's how you're going to have people simply match against protocols. :)
One thing I see mentioned in examples but not in the `__match__` definitions is how mappings work. Are you using `__match_args__` to map keys to attributes? Or are you using `__getitem__` and that just isn't directly mentioned? Otherwise the section on how `__match__` is used only mentioned attributes and never talks about keys.

Oh, __match__ is *only* used for class patterns. Mapping patterns are done differently. They don't use __getitem__ exactly -- the PEP says

Matched key-value pairs must already be present in the mapping, and not created
on-the-fly by ``__missing__`` or ``__getitem__``.  For example,
``collections.defaultdict`` instances will only match patterns with keys that
were already present when the ``match`` block was entered.

You shouldn't try to depend on exactly what methods will be called -- you should just faithfully implement the Mapping protocol.

OK, so `__contains__` then.

--Guido van Rossum (python.org/~guido)
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/N7USX5OB2NEPO25JLTMTI4SUQ2CB7WLY/
Code of Conduct: http://python.org/psf/codeofconduct/