[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