[Python-Dev] Re: super() harmful?

James Y Knight foom at fuhm.net
Fri Jan 7 18:45:53 CET 2005


On Jan 6, 2005, at 12:13 PM, Guido van Rossum wrote:
> So it has nothing to do with the new paradigm, just with backwards
> compatibility. I appreciate those issues (more than you'll ever know)
> but I don't see why you should try to discourage others from using the
> new paradigm, which is what your article appears to do.

This is where I'm coming from:
In my own code, it is very rare to have diamond inheritance structures. 
And if there are, even more rare that both sides need to cooperatively 
override a method. Given that, super has no necessary advantage. And it 
has disadvantages.
- Backwards compatibility issues
- Going along with that, inadvertent mixing of paradigms (you have to 
remember which classes you use super with and which you don't or your 
code might have hard-to-find errors).
- Take your choice of: a) inability to add optional arguments to your 
methods, or b) having to use *args, **kwargs on every method and call 
super with those.
- Having to try/catch AttributeErrors from super if you use interfaces 
instead of a base class to define the methods in use.

So, I am indeed attempting to discourage people from using it, despite 
its importance. And also trying to educate people as to what they need 
to do if they have a case where it is necessary to use or if they just 
decide I'm full of crap and want to use it anyways.

>> In order to make super really nice, it should be easier to use right.
>> Again, the two major issues that cause problems are: 1) having to
>> declare every method with *args, **kwargs, and having to pass those 
>> and
>> all the arguments you take explicitly to super,
>
> That's only an issue with __init__ or with code written without
> cooperative MI in mind. When using cooperative MI, you shouldn't
> redefine method signatures, and all is well.

I have two issues with that statement. Firstly, it's often quite useful 
to be able to add optional arguments to methods. Secondly, that's not a 
property of cooperative MI, but one of cooperative MI in python.

As a counterpoint, with Dylan, you can add optional keyword arguments 
to a method as long as the generic was defined with the notation #key 
(specifying that it will accept keyword arguments at all). This is of 
course even true in a single inheritance situation like in the example 
below.

Now please don't misunderstand me, here. I'm not at all trying to say 
that Python sucks because it's not Dylan. I don't even particularly 
like Dylan, but it does have a number of good ideas. Additionally, 
Python and Dylan differ in fundamental ways: Python has classes and 
inheritance, Dylan has generic functions/multimethods. Dylan is (I 
believe) generally whole-program-at-a-time compiled/optimized, Python 
is not. So, I think a solution for python would have to be 
fundamentally different as well. But anyways, an example of what I'm 
talking about:

define generic g (arg1 :: <number>, #key);
define method g (arg1 :: <number>, #key)
   format-out("number.g\n");
end method g;

define method g (arg1 :: <rational>, #key base :: <integer> = 10)
   next-method();
   format-out("rational.g %d\n", base);
end method g;

define method g (arg1 :: <integer>, #key)
   next-method();
   format-out("integer.g\n");
end method g;

// Prints:
// number.g
// rational.g 1
// integer.g
g(1, base: 1);

// Produces: Error: Unrecognized keyword (base) as the second argument 
in call of g
g(1.0, base: 1);

> Cooperative MI doesn't have a really good solution for __init__.
> Defining and calling __init__ only with keyword arguments is a good
> solution. But griping about "traditionally" is a backwards
> compatibility issue, which you said you were leaving behind.

Well, kind of. In my mind, it was a different kind of issue, as it 
isn't solved by everyone moving over to using super. As nearly all the 
code that currently uses super does so without using keyword arguments 
for __init__, I considered it not so much backwards compatibility as a 
re-educating users kind of issue, the same as the requirement for 
passing along all your arguments.

> Exactly. What is your next_method statement supposed to do?

Well that's easy. It's supposed to call the next function in the MRO 
with _all_ the arguments passed along, even the ones that the current 
function didn't explicitly ask for. I was afraid you might ask a hard 
question, like: if E2 inherits C's __init__, how the heck is it 
supposed to manage to take two arguments nonetheless. That one I 
*really* don't have an answer for.

> No need to reply except when you've changed the article. I'm tired of
> the allegations.

Sigh.

James



More information about the Python-Dev mailing list