Guido van Rossum wrote:
> On Wed, Mar 31, 2021 at 2:14 PM Brandt Bucher brandtbuc...@gmail.com
> wrote:
> > (One change from my last email: it doesn't allow `__match_map__` /
> > `__match_seq__` to be set to `False`... only `True`. This prevents some
> > otherwise tricky multiple-inheritance edge-cases present in both of our
> > flagging systems that I discovered during testing. I don't think there are
> > actual use-cases for unsetting the flags in subclasses, but we can revisit
> > that later if needed.)
> That's surprising to me. Just like we can have a class that inherits from
> int but isn't hashable, and make that explicit by setting `__hash__ =
> None`, why couldn't I have a class that inherits from something else that
> happens to inherit from Sequence, and say "but I don't want it to match
> like a sequence" by adding `__match_sequence__ = False`? AFAIK all Mark's
> versions would support this by setting `__match_kind__ = 0`.

The issue isn't when *I* set `__match_seq__ = False` or `__match_container__ = 
0`. It's when *one of my parents* does it that things become difficult.

> Maybe you can show an example edge case where this would be undesirable?

Good idea. I've probably been staring at this stuff for too long to figure it 
out myself. :)

As far as I can tell, these surprising cases arise because a bit flag can only 
be either 0 or 1. For us, "not specified" is equivalent to 0, which can lead to 
ambiguity.

Consider this case:

```
class Seq:
    __match_seq__ = True
    # or __match_container__ = MATCH_SEQUENCE

class Parent:
    pass

class Child(Parent, Seq):
    pass
```

Okay, cool. `Child` will match as a sequence, which seems correct. But what 
about this similar case?

```
class Seq:
    __match_seq__ = True
    # or __match_container__ = MATCH_SEQUENCE

class Parent:
    __match_seq__ = False
    # or __match_container__ = 0

class Child(Parent, Seq):
    pass
```

Here, `Child` will *not* match as a sequence, even though it probably should. 
The only workarounds I've found (like allowing `None` to mean "this is unset, 
don't inherit me if another parent sets this flag", ditching tp_flags entirely, 
or not inheriting these attributes) feel a bit extreme just to allow some users 
to do the moral equivalent of un-subclassing `collections.abc.Sequence`.

So, my current solution (seen on the branch linked in my earlier email) is:

- Set the flag if the corresponding magic attribute is set to True in the class 
definition
- Raise at class definition time if it's set to anything other than True
- Otherwise, set the flag if any of the parents set have the flag set

As far as I can tell, this leads to the expected (and current, as of 3.10.0a6) 
behavior in all cases. Plus, it doesn't break my mental model of how 
inheritance works.
_______________________________________________
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/R3BGDN6NINJMLUWBVMVYIGORSLPJOMJP/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to