<br><div><span class="gmail_quote">On 4/19/06, <b class="gmail_sendername">Greg Ewing</b> <<a href="mailto:greg.ewing@canterbury.ac.nz">greg.ewing@canterbury.ac.nz</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Thomas Wouters wrote:<br><br>> The arguments against super() are<br>> understandable -- if you only think about your own class, or completely<br>> disregard MI. I think that's irresponsible: super() always calls the
<br>> right baseclass method,<br><br>On the contrary, it's precisely when you *don't* know<br>what classes are going be mixed in with you that super()<br>is likely to go haywire.</blockquote><div><br>No, really, on the contrary, it's precisely when you don't know what classes are going to be mixed in with you that super() is what you need to use. If you do not use super(), you *will* be calling the wrong method. If you do use super(), you will be calling the right method, but you *may* pass the wrong arguments. The set of failure cases is very simply just smaller for super()-using classes.
<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"> Your super() call ends up<br>calling a method that you know nothing about,</blockquote>
<div><br>This is violence inherent in the system. This is *why* you're calling the baseclass method. You don't want to figure out the work yourself, you want to ask your baseclass "do your thing as if I weren't there and you got these arguments". The only assumption you make is that the method signature is compatible, and that is indeed unfortunate (but unavoidable, in the current state of affairs. Exclusively using keyword arguments helps a bit, though.)
<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">and the method being called isn't expecting to be called<br>in that context either.
</blockquote><div><br>A method that isn't expecting to be called by subclasses sounds like a broken method.<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Whether that will do the<br>"right" thing, or whether there even is a right thing<br>to be done, is anybody's guess.</blockquote><div><br>If two methods of the same name on different classes do wildly different things, your class hierarchy is broken, and it's completely unrelated to using super() or not. If you want the 'left' part of the diamond to take care of method 'spam' even though the 'right' part of the diamond also defines 'spam', not using super() will do what you want -- except it's horribly fragile. As soon as the right part of the diamond calls spam (and expects the right-handed spam to be called, which it can't help but do) things blow up; it will get the left-handed spam instead. That situations in unfixably broken. Using super() just makes the break more apparent (and, apparently, gives you an easy target to blame :-)
<br><br>If you have two methods of the same name that do the same thing, and expect to be called in the same situations, but have incompatible function signatures, it is also unfixably broken. When you use super(), the left side ends up calling the right-handed method as if it was the baseclass method, possibly passing too few arguments or the wrong ones, or not passing a bit of extra information the right-side could have used. When you don't use super(), you end up ignoring the right hand side entirely, quite likely breaking the entire functionality of that part of the inheritance tree.
<br><br>And if you have two methods that don't have a signature incompatible from the baseclass signature (meaning any extra arguments are optional), super() does the right thing but explicit baseclass calls do not. It's as simple as that.
<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">What causes trouble isn't multiple inheritance, it's<br>diamond inheritance.</blockquote>
<div><br>Sorry, that's wishful thinking. Multiply-inheriting classes in Py3K are always involved in diamond inheritance, because they are always what we now call "new-style". And it's not an insignificant diamond, 'object' provides methods such as __getattribute__ that are really necessary, and really used.
<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"> Without diamond inheritance,<br>explicit calls to inherited methods usually work fine,
<br>and continue to work fine when your classes get<br>inherited, multiply or otherwise, by other people's<br>classes, as long as they do something sensible with<br>their inherited calls.</blockquote><div><br>No, as long as there is *no* conflict between the methods of the two sides. Assuming that is, again, wishful thinking, since you have no control over what subclasses do. And if they 'do something sensible', super() *also* does the right thing -- it just does the right thing in more cases to boot.
<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Personally I think that the use of diamond inheritance<br>should be severely discouraged, if not banned completely.
<br>There's a fundamental problem with it: different<br>subclasses can have different ideas on how the diamond-<br>inherited class should be initialised, and otherwise<br>used. That seems to me an inherent flaw in the notion
<br>of diamond inheritance, and not something that super()<br>or anything else can fix.</blockquote><div><br>As Guido pointed out, diamond inheritance isn't fundamentally flawed, it just requires a level of co-operation we aren't explicitly requiring, in Python. Fortunately, Python is quite flexible, and we can add that requirement in a custom metaclass. It would walk the namespace of any newly created class, recording method signatures, and comparing them against signatures of baseclasses. Or we could use decorators to indicate willing co-operation and warn against methods of the same name that don't say they play well with others. I've thought about using a metaclass like that, but I end up not needing it enough. Likewise, if you insist on not using MI (or super()), a metaclass could easily be made to warn against uses of MI -- and I did make that one for someone, once:
<br> <br>import warnings<br><br>class DontMIType(type):<br> def __init__(self, name, bases, dict):<br> if bases and len(bases) > 1:<br> # Find the first baseclass to be of our type<br> firstbase = self
<br> for base in bases:<br> if not isinstance(base, DontMIType):<br> break<br> firstbase = base<br> warnings.warn("Class %s multiply inherits, but baseclass %s "
<br> "disallows multiply inheriting" % (self, firstbase))<br> return super(DontMIType, self).__init__(name, bases, dict)<br><br>It's only avisory, because you can easily circumvent this metaclass in subclasses by subclassing the metaclass and not calling the base-metaclass __init__, then using the sub-metaclass as metaclass for subclasses of whatever class doesn't like participating in MI. Besides, mandating such things isn't very Pythonic. It's a clear enough signal that the gun is now pointed at your wriggly little toes.
<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Whenever I've tried to use diamond inheritance, I've<br>always ended up regretting it, and re-designing my class
<br>hierarchy to eliminate it. Once I've done that, any<br>reason I had to use super() invariably disappears.</blockquote><div><br>If you have that luxury, that's fine. I'd encourage anyone to avoid MI (and use the above metaclass to avoid stepping into unexpected puddles later in life, of course.) I tend to use metaclasses instead of MI myself -- except *in* metaclass hierarchies, but that has a practical reason: Python *does* require metaclass compatibility. Metaclasses make for a good example on how (and why) to use super(), because the methods you use on metaclasses (by and large) are the __init__, __new__, __getattribute__ and __setattribute__ methods, and changing their signature is folly.
<br><br>But there are actual use-cases for MI in 'normal' classes, too, and Python still has to try and cater to them as best it (and we) can. And super() is part of that.<br></div><br></div>-- <br>Thomas Wouters <<a href="mailto:thomas@python.org">
thomas@python.org</a>><br><br>Hi! I'm a .signature virus! copy me into your .signature file to help me spread!