
On Tue, 5 Apr 2022 at 03:58, malmiteria <martin.milon@ensc.fr> wrote:
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".
This right here, this is the fundamental problem. When you call super(A, self), you are expecting to call A's method. This is simply wrong. This is not super's job. If you want to call A's method, call A.method(self). Don't call super. If you want to call the next method after A, use super(A, self). And most of the time, what you want is "the next method after this class", which is super(__class__, self), and can be abbreviated super(). You are working around super because you assume that every call must go through it. That's simply not the case. You are working around *your own misunderstanding of super*, and then blaming super for your awkwardness. *STOP USING SUPER* where it's the wrong tool for the job. Your problems will vanish.
Again, this sounds like inheritance is the wrong tool here. Nnot everything is an inheritance relationship. Nnot the only one making typos hehe :p
I never ask people to avoid making any typos... but I do ask people to test *code blocks* before posting them. (And, yes, I have been guilty of posting untested and buggy code blocks. But you'd be fully justified in calling me out on that one.)
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.
They're closely linked. The MRO exists, and super is used as a means of skipping part of it.
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.
Python *already has* all these strategies. Some of them involve the use of super. Some do not.
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.
Is super the wrong tool for the job? Don't use super. Python's integer type has some fairly severe limitations, notably that it can't handle fractional values. Let's change the int type to be more intuitive - dividing an int by an int should return an int, with the exact value of that fraction. So 17/3 should return an int with the value of five and two thirds. That's intuitive, right? Today's int type has this weird limit. Or maybe I should be using Fraction or float instead of int. Maybe that's a better solution.
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.
Is it a problem that super doesn't handle this (somewhat weird and extremely hypothetical) situation? You can use explicit method resolution instead. ChrisA