
Steven D'Aprano writes:
feature 1 (of super alone): proxying the parent. What most people think super does (and expect it to do): it allows to call method from *the* (most people don't think of multiple inheritance) parent. For single inheritance, that is exactly what it does, and there is no problem. Just use super() and it Just Works.
I 100% agree. I don't see a problem with super and MRO for today's single inheritance. That's why I explicitely care to make my porposal equivalent to today's super and MRO in single inheritance scenarios.
It can be used by working around MRO to proxy any parent directly. I don't know what you mean by this. Why are you "working around" the MRO?
super(A, self) does not proxy to A, but to the first *after* A in MRO order. When you're actually in need to passing arguments to super, you very likely know what class you're gonna be targeting, and having to run MRO logic in reverse to call super to the class that comes first before your target in MRO order is what i refer to as "working around MRO".
feature 2 (of super + MRO): sideway specialization / mixins This is just a form of multiple inheritance where the mixins are not designed to be instantiated themselves.
Actually, one could argue that this is a case of "I need to have the exact same child applied to multiple possible parents". ML today is the way to go, but i propose a dedicated syntax: ``` class MyView( Mixin1( Mixin2( View ) ) ): ... ``` which allows to own up to this inheritance that we couldn't refactor as single inheritance before.
feature 3 (of super + MRO): dependency injection / inheritance tree alteration I don't know what you mean by dependency injection here.
Essentially since MRO is just an order, you can create classes that would 'intercept' super calls. By producing an inheritance tree such that your injected class is ordered between your target classes. This is a classic exemple use case of super and MRO that raymond hettinger talks super being super dives into.
Inheritance tree modification... I think that means you want to copy a class hierarchy, but with changes? Yep, that's another, more straightforward way to inject a class in any inheritance tree.
Again, this sounds like inheritance is the wrong tool here. Nnot everything is an inheritance relationship. Nnot the only one making typos hehe :p
Actually, the (honestly debatable) use case is to mock one parent class that would eventually do actual API calls, so that your tests can mock those API calls without having to mock the child class. I think that's exactly the exemple raymond hettinger gave in his talk, i'm not sure.
feature 4 (of MRO alone): method resolution This is the one and only thing that super() if for. Well to be precise, its not just methods, but any attributes. super does not provide method resolution. MRO gives the order in which attribute / method would be looked up for.
``` class A: def method(self): pass class B(A): pass B().method() # works despite B body not declaring "method", and resolves to the method defined in A body. ``` This is method resolution. super is not a part of it Although, super do rely on it, since it will target the next in MRO order to select the class to proxy.
The diamond problem is a feature of multiple inheritance with diamonds. super() can't solve it in the fully general case because there is no general solution. That's why my proposal includes a inheritence strategy module, which would allows users to pick and choose which kind of strategy they need. It would default to the current strategy which consists of calling the parent that apppears multiple times in an inheritance tree only on its last occurence. Other strategy could be to call parent that appear multiple times on each occurence, or even to specify which occurence should be called, and which should be ignored. That's a "no general solution" problem solved.
What problems? Here you are talking about *the* parent, so we have single inheritance: "proxying the parent" is simply how i named this feature, i do not imply this to apply only in simple inheritance scenarios.
with the use of super, it could look like that, intuitively Not it can't. This is wrong. You have misunderstood what super does. I am very aware of super's behavior, at this point i'm simply showcasing a use case of super, from the point of view of the average developper. Note that i'm not saying this is what the solution is, but what it "could look like, """"" intuitively """"" ".
is to try (and fail!) to use inheritance for behaviour which needs to be modelled by delegation. [...] And you provide the right solution: delegation. Today's right solution. Again, i'm showcasing a limit of today's super.
By definition, inheritance requires HalfBreed to call the methods of all three superclasses. (That is at least the definition used in Python, other languages may do differently.) If HalfBreed is not using the methods of all its superclasses, it is not really an inheritance relationship. By this definition, the behavior i wanna implement in HalfBreed is one of inheritance, as it is using the methods of all its superclasses. As you were quick to point out, super does not cover this scenario, which is the problem i'm highlighting with this example.
we lose the proxy feature, which to be fair, is aqueen to syntactic sugar. But this is still a feature loss. How do you lose a feature you don't want?
You still want the syntactic sugar of not having to pass self as first argument of the parent methods. What we do not want is the inappropriate (in this exemple, not in general) way super will visit all the parents method
we lose the sideway specialisation, coming from super's behavior, which, in this case, is the goal, so we're not complaining. What sideway specialisation? You have no mixin classes here. Yep, I'm just trying to be exhaustive in my analysis.