
I'm a bit late to this conversation, but here i go: Steven d'Aprano writes:
But given the assumptions that:
- the inheritance model automatically resolves conflicts;
- the MRO is entirely dependendent on the shape of the inheritance graph, and not on incidental properties like the name of classes;
- the inheritance model is consistent, monotonic and preserves local precedence order (C3 linearization);
I believe that those are a bit too much. conflicts can be resolved by redefining the method in the child class, so no need for automation here. As long as super calls allow to pick and chose the parent method you want, so you can explicitely combine them as you want, in the order you want, or simply ignore one if you want. So i wouldn't define 'full MI' with the assumption that "the inheritance model automatically resolves conflicts;" One could say it even gives more power to the programmers, as it would inform them in those 'ambiguous' cases.
- the MRO is entirely dependendent on the shape of the inheritance graph, and not on incidental properties like the name of classes; This is something we want, yeah, but it is not a given in python...
class Top: pass
class Left(Top): pass
print(Left.__mro__) # Left, Top
class Right(Top): pass
class Bottom(Left, Right): pass
print(Bottom.__mro__) # Bottom, Left, Right, Top
As you can see, Left MRO when subclassed by Bottom is different from Left MRO when taken alone. (even if it can be found in a subsequence) This means that a refactoring consisting of extracting the class Top from Left and Right is technically a breaking change, from a lib author point of view. We might wanna get rid of that.
- the inheritance model is consistent, monotonic and preserves local precedence order (C3 linearization); I'm unclear on what you mean by consistent. Local precedence order should probably be conserved, i'm not arguing against that.
But monotonicity, i don't think so. with the exemple above, Bottom MRO could be "Bottom, Left, Top, Right, Top", this is not monotonic, but not inconsistent either. Probably even more consistent? essentially, it could be for any class : "class, [MRO from class first parent], [MRO from the second parent], ..." That would be even more consistent than today's MRO which by subclassing allows MRO injection And there would not be any inconsistent inheritence tree, except maybe if a class happens to be in its own inheritance tree. You also argued somewhere, sorry i can't find it back to quote it, that it's a good thing that an error is raised in case we're doing an inconsistent class hierarchy, but i'd argue it is a problem, since there's no way out this error. Even when you know what you're doing. Those class inheritence trees are barred from the language now, no matter what. Greg Ewings writes:
There's nothing incoherent or inconsistent about the way C++ and Eiffel do MI. The main difference is that they require you to explicitly resolve conflicts between inherited methods -- which is arguably more Pythonic than Python, since they refuse the temptation to guess. That's actually the very reason why i named this thread "mro and super don't feel so pythonic" Can't agree more with you here.