<br><br><div><span class="gmail_quote">On 4/20/07, <b class="gmail_sendername">Guido van Rossum</b> <<a href="mailto:guido@python.org">guido@python.org</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;">
On 4/20/07, Thomas Wouters <<a href="mailto:thomas@python.org">thomas@python.org</a>> wrote:<br>> I've had this near the top of my (Python) TODO list for a while, but I<br>> haven't been able to find the time. I've considered it while doing the
<br>> dishes and such, though.<br><br>(Not in the shower? :-)</blockquote><div><br>Yes, there too, when I shower alone; I was going to spare everyone the visual 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;">
> I can think of two ways of doing the underlying<br>> magic "properly", and one way that's too ugly to think about:<br>><br>> 1) Add a new type of descriptor-hook, for associating an object with the
<br>> class it is an attribute of. After class creation (in the metaclass<br>> __init__), any object with this __associate__ (or whatever) hook gets it<br>> called. It's only called for objects that are attributes of *that* class,
<br>> not of any superclasses (since they will already be associated with the<br>> superclass.) I'm sure there are other uses for this hook, just not methods<br>> that want to use super() -- like zope interfaces ;)
<br><br>Nice and elegant. Though what would the hook *do*? I.e. where does it<br>store the class reference for super to find? Perhaps this is where my<br>idea of a designated cell comes in handy (although you'd end up with a
<br>cell per method instead of all methods sharing one cell).<br><br>Also, what arguments are passed to the hook? For this purpose the<br>class object is the only thing needed -- but is that always<br>sufficient?</blockquote>
<div><br>The hook would 'bind' the function to the class -- in some unspecified way. Unspecified because I haven't thought that far ahead yet, and I don't forsee any particular difficulties. Either the function gets wrapped in an 'associated function' type that knows which class it was defined in (so somewhat different from the current 'unbound method' type, but not much) or we just store the associated-class in the existing function object (probably the better option.). In either case we need some new magic to pass this class-object to the actual code object, or give the code object a way to refer to the function object (sometimes also useful for other reasons; it's not an uncommon request, in newbie areas.)
<br><br>As for the arguments to this hook -- I guess passing the attribute name as well as the class object makes sense. It's not much more overhead, and there isn't much more we could sensibly pass that isn't easily available given the class object and attribute name.
<br><br>Phillip mentioned class decorators -- I'd forgotten about those. I don't see much use for them myself, as metaclasses make much more sense to me, in particular because they are naturally inherited, whereas class decorators are (I assume) not inherited. I'm not sure how they should -- or could -- work together with super. It would only be a problem if the class decorator returns a wrapper class, rather than mutate the class. I guess we'd need a way to tell associated-functions "instead of ever visiting this class, visit this wrapper class instead. But don't mess with MRO"... I think. I'm not entirely sure how class decorators would affect MRO, really.
<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;">> 2) Add a new argument to __get__ (or a new method that acts like __get__
<br>> but with the extra argument, and is called instead of __get__ if it is<br>> defined) where the extra argument is the class that the retrieved descriptor<br>> is actually an attribute of. It currently (correctly) gets the class the
<br>> attribute was retrieved through, which could be a subclass.<br><br>I'm not so keen on this; calling an existing API with an extra<br>argument is fraught with transitional problems (2to3 notwithstanding).<br>And checking for two different special methods slows things down. I'd
<br>propose to pass the class where it's found as the 3rd arg always,<br>since (almost) nobody uses this argument, but I'm not sure of the<br>consequences for class methods.</blockquote><div><br>The consequence for classmethods would be bad. They would always get the class they were defined on as first argument, making them completely pointless. So, let's not do that :)
<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;">(Of course, there's the issue what to do if we dynamically define a<br>new function, and poke it into a class as a method, and that function
<br>needs to use super. IMO it's fine to require such a function to use<br>the underlying super() machinery -- this must be an exceedignly rare<br>case!)</blockquote><div><br>It's easy to handle such cases if we flag super-syntax-using-functions specially (which is also easy.) type's __setattr__ can complain if such a function gets assigned to an attribute, or it could do the binding magic right then. Functions that don't use the super syntax will continue to work like usual. And super-syntax-using-functions can scream and shout when they get 'associated' with more than one class, of course.
<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;">> In both these cases, the (un)bound method object would end up with knowledge
<br>> of the class it is defined in, and create a local variable with a<br>> super-object for the 'super' keyword to use.<br><br>Ah, so you propose to store it in a local variable. But where is it<br>stored before the function is called? I guess on the "bound method"
<br>object. But how is the value passed on as part of the call? I like a<br>cell a lot better because we have an established way to pass cells<br>into calls.</blockquote><div><br>As I mentioned above, I didn't really think about this part. By 'local variable' I just mean that we don't use a global registry or some such ugly hack -- it's a reference, stored wherever, specific to that call.
<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;">> There still are some grey areas<br>> to solve -- what if classes share functions, what if functions share
<br>> code-objects, etc. #2 is probably a better way to go about it than #1, in<br>> that regard.<br><br>Sharing functions is very rare and IMO it's okay if the mechanism<br>doesn't work in that case -- as long as it fails loudly. Sharing code
<br>objects shouldn't be a problem -- code objects are immutable anyway,<br>cells are associated with the function object, not with the code<br>object.</blockquote><div><br>Agreed. <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;">
> There's also the question of what the super keyword itself should look like,<br>> e.g.<br>><br>> # declaration-style, no dot<br>> res = super currentmethod(arg, arg)<br>> # treat super like self
<br>> res = super.currentmethod (arg, arg)<br>> # treat super like self.currentmethod<br>> res = super(arg, arg)<br>><br>> I think super.currentmethod(arg, arg) makes the most sense, but that may be<br>
> because it most closely resembles the current practice. However, it may call<br>> the "wrong" supermethod when the class does, for instance, '__repr__ =<br>> __str__'.<br><br>Depends on how you define "wrong". :-)
</blockquote><div><br>That's why it's in "quotes" :) No matter what we do, it will always be wrong for someone somewhere, I'm sure.<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;">
I am strongly in favor of super.currentmethod(...) if only because<br>that's closest to how we've always done it, and there may even be a<br>use case for callong some *other* super method.</blockquote><div><br>I agree. The big downside of thinking of these things off-line (like in the shower) is that it's hard to visualize the actual code. The moment I wrote down the three alternatives I'd imagined, I realized '
super.currentmethod()' is the only sane spelling ;)<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-eating-signature-virus-resistant .signature virus! copy me into your .signature file to help me spread!