Re: [Python-ideas] [Python-Dev] python and super

(Moving this thread to python-ideas, as it seems better suited for here). On 04/15/2011 11:02 AM, Michael Foord wrote:
Yup.
Right. I agree that the current behavior of super in that regard is surprising, but I don't see how the "go ahead and call sibling methods anyway" fix is plausible. What happens to the return value of that call? There's nowhere for it to go - super() would have to somehow implicitly integrate two different return values, which is all kinds of bad magic. Consider these classes: class UncooperativeBase: def method(self): # look Ma, no super() call! return ["UncooperativeBase"] class OtherBase: def method(self): return ["OtherBase"] + super().method() class Child(UncooperativeBase): def method(self): return ["Child"] + super().method() class GrandChild(Child, OtherBase): def method(self): return ["GrandChild"] + super().method() Currently, OtherBase.method() is never called, because UncooperativeBase.method() breaks the super() chain. Any proposal to have super() ensure that OtherBase.method() is called needs to explain what exactly happens to its return value. This would normally be handled explicitly by UncooperativeBase, since it would call super() and do something with the return value. But with the explicit chain broken, you end up with two different chains, and at some point their return values would need integrating. Carl

On Fri, Apr 15, 2011 at 12:42 PM, Carl Meyer <carl@oddbird.net> wrote:
I feel like you're implying this would be fixed by having UncooperativeBase call super().method(), but this would not make working code. _It's the base class's responsibility *not* to call super._ If UncooperativeBase called super() and we called GrandChild().method(), then we would call our three superclasses's method methods and object's. the problem is that object doesn't even HAVE a method method, so we'll get an error. (For the very common example of __init__, object *IS* the shared superless base class with the method we want, but we need our own shared superless base class for arbitrary methods.) This isn't a problem I know a technical solution to—we can't have two independent base classes with the same method. If they are related to each other, they need to share a base class that probably doesn't do anything exciting. If they're truly unrelated, then we don't want to be calling them interchangeably in the MRO and we need to give them different names, perhaps using a proxy class with one that calls into the other. Another solution that is much cleaner is to use composition for one or both of the classes involved. This only works if these are concrete classes, obviously, but gets us tons of benefits. It's not at all complicated to decide what needs to be called when, change names, or pick-and-choose what functionality to re-use. Mike

Hi Mike, On 04/15/2011 01:00 PM, Mike Graham wrote:
That's right, though only distantly related to my point. I was just too aggressive in cutting the example down to a minimal number of classes; UncooperativeBase and OtherBase should share a superclass with method(), call it GrandParent. My point still applies the same: if UncooperativeBase doesn't call super().method(), it's not feasible for super to call OtherBase.method() (the "call siblings anyway" feature that's been requested in this thread), because it would introduce the need to somehow magically "integrate" the return values from OtherBase.method() and UncooperativeBase.method().
Right. This (unrelated base classes with the same method) was just an error in my example, not a problem I am trying to propose a solution to.
Agreed. Carl

Mike Graham wrote:
I would say it's also the responsibility of every class taking part in the chain to inherit directly or indirectly from the common base class that defines the terminating method, to ensure that it appears last in the mro. -- Greg

On Fri, Apr 15, 2011 at 12:42 PM, Carl Meyer <carl@oddbird.net> wrote:
I feel like you're implying this would be fixed by having UncooperativeBase call super().method(), but this would not make working code. _It's the base class's responsibility *not* to call super._ If UncooperativeBase called super() and we called GrandChild().method(), then we would call our three superclasses's method methods and object's. the problem is that object doesn't even HAVE a method method, so we'll get an error. (For the very common example of __init__, object *IS* the shared superless base class with the method we want, but we need our own shared superless base class for arbitrary methods.) This isn't a problem I know a technical solution to—we can't have two independent base classes with the same method. If they are related to each other, they need to share a base class that probably doesn't do anything exciting. If they're truly unrelated, then we don't want to be calling them interchangeably in the MRO and we need to give them different names, perhaps using a proxy class with one that calls into the other. Another solution that is much cleaner is to use composition for one or both of the classes involved. This only works if these are concrete classes, obviously, but gets us tons of benefits. It's not at all complicated to decide what needs to be called when, change names, or pick-and-choose what functionality to re-use. Mike

Hi Mike, On 04/15/2011 01:00 PM, Mike Graham wrote:
That's right, though only distantly related to my point. I was just too aggressive in cutting the example down to a minimal number of classes; UncooperativeBase and OtherBase should share a superclass with method(), call it GrandParent. My point still applies the same: if UncooperativeBase doesn't call super().method(), it's not feasible for super to call OtherBase.method() (the "call siblings anyway" feature that's been requested in this thread), because it would introduce the need to somehow magically "integrate" the return values from OtherBase.method() and UncooperativeBase.method().
Right. This (unrelated base classes with the same method) was just an error in my example, not a problem I am trying to propose a solution to.
Agreed. Carl

Mike Graham wrote:
I would say it's also the responsibility of every class taking part in the chain to inherit directly or indirectly from the common base class that defines the terminating method, to ensure that it appears last in the mro. -- Greg
participants (3)
-
Carl Meyer
-
Greg Ewing
-
Mike Graham