
On Wed, 5 Jan 2005 18:00:38 -0500, James Y Knight <foom@fuhm.net> wrote:
On Jan 5, 2005, at 1:23 PM, Guido van Rossum wrote:
The issue of mixing super() and explicit calls to the superclass's method occur with any method. (Thus making it difficult/impossible for a framework to convert to using super without breaking client code that subclasses).
Well, client classes which are leaves of the class tree can still safely use BaseClass.thisMethod(self, args) -- it's only classes that are written to be extended that must all be converted to using super(). So I'm not sure how you think your clients are breaking.
See the section "Subclasses must use super if their superclasses do". This is particularly a big issue with __init__.
I see. I was thinking about subclassing a single class, you are talking about subclassing multiple bases. Subclassing two or more classes is *always* very subtle. Before 2.2 and super(), the only sane way to do that was to have all except one base class be written as a mix-in class for a specific base class (or family of base classes). The idea of calling both __init__ methods doesn't work if there's a diamond; if there *is* a diamond (or could be one), using super() is the only sane solution.
Adding optional arguments to one branch of the inheritance tree, but not another, or adding different optional args in both branches. (breaks unless you always pass optional args as keywordargs, and all methods take **kwargs and pass that on to super).
But that breaks anyway; I don't see how using the old Base.method(self, args) approach makes this easier, *unless* you are using single inheritance. If you're expecting single inheritance anyway, why bother with super()?
There is a distinction between simple multiple inheritance, which did work in the old system
Barely; see above.
vs. multiple inheritance in a diamond structure which did not work in the old system. However, consider something like the following (ignore the Interface/implements bit if you want. It's just to point out a common situation where two classes can independently implement the same method without having a common superclass):
class IFrob(Interface): def frob(): """Frob the knob"""
class A: implements(IFrob) def frob(self, foo=False): print "A.frob(foo=%r)"%foo
class B: implements(IFrob) def frob(self, bar=False): print "B.frob(bar=%r)"%bar
class C(A,B): def m(self, foo=False, bar=False): [I presume you meant from instead of m here] A.m(self, foo=foo) B.m(self, bar=bar) print "C.frob(foo=%r, bar=%r)"%(foo,bar)
Now, how do you write that to use super?
The problem isn't in super(), the problem is that the classes A and B aren't written cooperatively, so attempting to combine them using multiple inheritance is asking for trouble. You'd be better off making C a container class that has separate A and B instances.
And using multiple inheritance the old was was not confusing? Surely you are joking.
It was pretty simple until you start having diamond structures. Then it's complicated. Now, don't get me wrong, I think that MRO-calculating mechanism really is "the right thing", in the abstract. I just think the way it works out as implemented in python is really confusing and it's easy to be worse off with it than without it.
So then don't use it. You couldn't have diamonds at all before 2.2. With *care* and *understanding* you can do the right thing in 2.2 and beyond. I'm getting tired of super() being blamed for the problems inherent to cooperative multiple inheritance. super() is the tool that you need to solve a hairy problem; but don't blame super() for the problem's hairiness.
If they're happy with single inheritance, let them use super() incorrectly. It works, and that's what count. Their code didn't work right with multiple inheritance before, it still doesn't. Some people just are uncomfortable with calling Base.method(self, ...) and feel super is "more correct". Let them.
Their code worked right in M-I without diamonds before. Now it likely doesn't work in M-I at all.
If you have a framework with classes written using the old paradigm that a subclass must call the __init__ (or frob) method of each of its superclasses, you can't change your framework to use super() instead while maintaining backwards compatibility. If you didn't realize that before you made the change and then got bitten by it, tough. -- --Guido van Rossum (home page: http://www.python.org/~guido/)