
Steven D'Aprano writes:
It just means that Python handles more cases than Eiffel or C++ Does C++ or Eiffel ban some class inheritance tree like python does? I can't find sources on that, although, i didn't spend an hour looking for it. But if not, i would say that python handle less cases than C++ or Eiffel.
I don't know enough about those languages to answer that question. Although, in general, a language that doesn't ban any class inheritance trees, would feel more general to me, no matter if it's the case in C++ and Eiffel or not.
I think we agree that when we do this:
instance.method()
the interpreter automatically searches for some class in a tree of superclasses where the method is defined, and we call that inheritance. That's part of what I call inheritance, but i wanna point out that it doesn't imply that this wouldn't be inheritance if the resolution wasn't successful.
For exemple, i think nobody would deny the name inheritance even in case of an AttributeError. Same logic applies if we had an error in case there's multiple candidate for resolution. I would still call that inheritance.
If we had to manually inspect the tree of superclasses and explicitly walk it, it wouldn't be inheritance Well, yeah. But again, that doesn't imply this will always provide a resolution.
# Pretend that classes have a parent() method and we only # have single inheritance. instance.__class__.parent().parent().parent().method(instance)
which is just another way of explicitly calling a method on a class:
GreatGrandParentClass.method(instance)
So we're not inheriting anything there, we're just calling a function:
some_namespace.function(instance) In case you wanna refer an attribute of a parent, from within a child, the automatic resolution is in the way, and this parent feature, like super, is a way to resolve work around the inheritance resolution. It allows to resolve parent method from the context of the child I'm not sure i would call super (or super like features, like this 'parent') inheritance, but i see it as one feature in the set of feature that can be part of inheritance.
maybe i can put it as "super is in the inheritance namespace"
What else could distinguish inheritance from just "call some function", if it isn't that the interpreter works out where the function is defined for you, using some automatic MRO? I mean, it resolves it 'automatically' based on what you define in the end. But yeah, some resolution algorithm should be at play. Again, this algorithm can produce errors (like AttributeError), and overall, the idea of order "at all cost" might not need to be a part of it. Especially, i would still call it inheritance even if multiple branches aren't ordered from one another. Although, if there was no order between a class and it's parents, i'm not sure i would still consider it inheritance. I think a class should come before it's parents.
(That's not a rhetorical question. If you have some other distinguishing characteristic in mind, apart from automatically searching the MRO, then please do speak up, I would love to hear it.) I wouldn't feel too bad if someone told me inheritance without a super feature isn't inheritance, although, i would just consider it incomplete, but still inheritance.
Would you still call it inheritance if an error was raised in case multiple parent could provide a candidate for the resolution? Would you still call it inheritance if an error is raised when no resolution is possible? I'm trying to understand what you mean by automatic. I think we don't mean the same thing by it, so it might be a point where our understanding / definition of inheritance diverges. Based on earlier discussion we had, i think you mean that if you have, at any point, for any reason, to explicitely state what method should be "inherited" then it's not really inheritance anymore? So in this scenario: ``` class A: name = 'A' class B: name = 'B' class C(A,B): pass ``` If C.name was raising an error, you wouldn't consider it inheritance? Even if it was possible to define the attribute name in C (to remove the error)? I'm talking about an attribute access error here, not a class definition error. Actually i think it might be the case already with __slots__, except it's not even possible to redefine __slots__ in the child, the error persists, and it's a definition error, not an attribute access error: ``` class A: __slots__ = ("a") class B: __slots__ = ("b") class C(A,B): pass # raises a TypeError (multiple bases have instance lay-out conflict) class C(A,B): __slots__ = ('c') # raises the same error ```