
On Sat, Apr 16, 2022 at 11:07:00AM +1000, Chris Angelico wrote:
My view: If a class inherits two parents, in any meaning of the word "inherits" that follows the normal expectation that a subclass IS an instance of its parent class(es), then it's MI.
Inheritance and "is-a" relationships are independent.
In some languages (but not Python), mixins provide inheritance but not an "is-a" relationship. In Python, virtual subclassing provides "is-a" without inheritance.
Virtual subclassing is still subclassing, just implemented differently.
You are correct that virtual subclassing is still subclassing, but it doesn't provide inheritance.
from abc import ABC class Parrot(ABC): ... def speak(self): ... print("Polly wants a cracker!") ... @Parrot.register ... class Norwegian_Blue: ... pass ... bird = Norwegian_Blue() isinstance(bird, Parrot) True bird.speak() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Norwegian_Blue' object has no attribute 'speak'
What is "inheritance" if it isn't that is-a relationship? How do you distinguish inheritance from delegation?
Haven't you spent all of this thread quite happily distinguishing between using inheritance and composition/delegation until now? Okay. Subclassing is, as you say, an "is-a" relationship. Whether you use virtual subclassing or actual subclassing, if you can say: issubclass(Norwegian_Blue, Parrot) isinstance(Norwegian_Blue(), Parrot) and get True for both of them, then Norwegian_Blue "is-a" Parrot. (Note that there is a technical difference between subclass and subtype, which I don't think is relevent to Python, but let's not go there.) Inheritance is a mechanism where a "child object" automatically acquires the properties and behaviors of some "parent object". In Python, that is handled by the interpreter when the child subclasses from the parent (but not in virtual subclassing). The critical thing is that in the absense of overloading or overriding, calling Norwegian_Blue().speak() will inherit the method defined in Parrot. We get that inheritance from real, but not virtual, subclassing. Composition provides a "has-a" relationship. For the sake of brevity, in simple terms (which may not be completely accurate, please don't nit- pick just for the sake of nit-picking), we use composition when we write: class Car: def __init__(self): self.engine = Engine() In this example, Cars are not Engines, but they have an Engine. Hence composition. Delegation provides a mechanism of code-sharing separate from inheritance, and often used instead of inheritance, or to compliment it. One object delegates to another object if the first explicitly calls the second: # self is a Car instance. self.engine.start() Delegation and composition often go together, but they don't necessarily have to. One can delegate to an object "outside" of the class, although that technique is not often used in Python. But broadly speaking, if your instance uses: super().method() that's an inheritance call. (It is only needed when you overload method.) If you write something like: SomeClass.method(self) that's delegation. Objects can delegate to anything they like, but if they delegate to a superclass, we might call it inheritance even though it lacks the property of being automatically handled by the interpreter. So one might loosely say that inheritance is a special case of delegation. Note that in languages without any form of super() or "next_class" or whatever you call it, that sort of manual delegation may be the only way to overload an inherited method.
Is inheritance only a thing if it happens on the line of code that says "class X"? (Not the case in Pike.)
I don't think the syntax is important. You could say: @inherits_from(Parrot) class Norwegian_Blue: pass if you prefer. Defining the decorator is left as an exercise. I can't comment on Pike, since you haven't described how it behaves. As I said, in some languages mixins define inheritance without subclassing; in Python virtual subclasses define subclassing without inheritance.
Is inheritance only a thing if it happens as the class is first created? (Is the case with mixins.)
I don't understand what you mean here. Do you mean that mixins inject their methods into the class at creation time, and then no longer are referenced? That's not what happens in Python. Mixins use the same method resolution mechanism as other superclasses, which means it happens on demand, not at creation time.
class Mixin: ... def method(self): ... print("Creation time") ... class Spam(Mixin): ... pass ... Mixin.method = lambda self: print("Call time") Spam().method() Call time
-- Steve