
On Sat, Apr 16, 2022 at 05:27:57PM +1200, Greg Ewing wrote:
On 15/04/22 10:37 pm, Steven D'Aprano wrote:
If you look at languages that implement MI, and pick the implementations which allow it with the fewest restrictions, then that is "full MI".
I believe that Python (and other languages) allow MI with the smallest set of restrictions, namely that there is a C3 linearization possible
But before Python adopted the C3 algorithm, it was less restrictive about the inheritance graph.
Less restrictive, and *inconsistent* (hence buggy).
So by your definition, current Python does not do full MI!
No, I'm excluding inconsistent models of MI. Correctness is a hard requirement. Otherwise we get into the ludicrous territory of insisting that every feature can be implemented with one function: def omnipotent_function(*args, **kwargs): """Function which does EVERYTHING. (Possibly not correctly, but who cares?) """ return None There you go, now we can define an MRO for any class hierarchy imaginable, and dispatch to the next class in that hierarchy, using the same function. It won't work, of course, but if correctness isn't a hard requirement, what does that matter? :-)
If you have to manually call a specific method, as shown here:
https://devblogs.microsoft.com/oldnewthing/20210813-05/?p=105554
you're no longer using inheritance, you're doing delegation.
You could also say that Python automatically delegates to the first method found by searching the MRO.
Why is one of these delegation and not the other?
That is a very interesting question. As I mentioned earlier, there is a sense that all inheritance is a kind of delegation, and in languages without an explicit super() (or "nextclass", or whatever you want to call it), the only way to get inheritance when you overload a method is to use explicit delegation to your superclass. So we might say that all inheritance is delegation, but not all delegation is inheritance. We might even go further and say that any delegation to a superclass (not just the direct parent) is a form of manual inheritance. But in general, in ordinary language, when we talk about inheritance, we're talking about two (maybe three) cases: 1. Automatic inheritance, when your class doesn't define a method but automatically inherits it from its superclass(es). class Parent: def method(self): pass class Child(Parent): pass assert hasattr(Child, "method") 2. Automatic inheritance when your class overloads a method and calls super() manually to delegate to the superclass(es). class Child(Parent): def method(self): print("Overload") super().method() 3. And more dubiously, but commonly used, when people who don't like super(), or know about it, explicitly delegate to their parent in single inheritance: class Child(Parent): def method(self): print("Overload") Parent.method(self) # Oooh, flashbacks to Python 1.5 -- Steve