[Python-3000] pep 3124 plans (original) (raw)

Talin talin at acm.org
Tue Jul 24 06:44:00 CEST 2007


Phillip J. Eby wrote:

I just don't see that the things Greg is describing aren't equally applicable to traditional methods.

I wasn't going to get into this, but - since you asked :)

The short form of the argument is that being able to overload any function as a generic function retroactively changes the implicit contract of what that function is.

I agree with you that the problem of tracing down all of the places where a GF could dispatch to is analogous to tracing down all the places where a subclass could override a method.

I would argue, though, that the "subclass analogy" that you have raised (which is a good one) corresponds most closely to the "explicit overload" GF design. In other words, when I create a base class, I know at the time I am writing it that because it is a class, its methods may be overloaded by someone later; And this knowledge is something that I factor in to the design of the class as I am writing it.

(This foreknowledge is even more relevant in languages like C++ and Java where you can explicitly control on a per-method basis whether it is overridable or not. Regardless of what you think of these languages, I think we can all agree that programmers depend on the ability of the 'virtual' or 'final' keywords to control what subclass writers are able to do.)

So I would say that writing a subclass is exactly like explicitly declaring a generic function: At the time I write the function, I know that people may come along later and overload that function, and I factor that knowledge into the design of the function as I am writing.

By extension, I claim that your analogy breaks down when we start talking about adding overloads to a function that was not originally declared as generic. The reason is because in this case, the original author of the function did not expect that someone would be able to come along and overload it later.

The ability to overload has always been part of the implicit contract of creating a class. It has never been part of the implicit contract of writing a function or method. So essentially, you are going back to all the functions that have ever been written and changing that implicit contract retroactively.

(I'm not claiming that this can never be done, I'm explaining why you are getting this reaction from Greg and Guido.)

In the case of magic overloads, they too are explicitly declared: Only in this case, the explicit declaration either in the wrapper function (such as len(x)), or in some cases the 'declaration' is hidden inside the Python interpreter, but everyone knows about it (an example being init). More broadly, everyone knows in advance that a method having a name of the magic form is intended to be a specialization of a general pattern.

Now, it's not that hard, for a given function, to use grep to trace down the possible GFs that may be overloading that specific function.

But that's only if you have foreknowledge of which functions are overloaded and which aren't. There are thousands of functions in a typical program (well, more accurately there are thousands of methods, and relatively few global functions). Suppose that 5% of them are overloaded, but you have no idea which 5% of them are. Trying to search for each of them to see what overloads there are is an N^2 problem, and very different, I would claim, than the situation with subclassing.

(Although admittedly, this problem is really only acute when we talk about non-instance-method functions, since the implicit constraints on the 'self' parameter already limit the search space for possible overloads of instance methods. Although with adaption and bound methods, anything can act like an instance method, so I would guess all bets are off...)

Now, it may be interesting to compare the implicit overloading with C++ overloaded methods. C++ also allow any function to be overloaded without explicitly declaring "overloadability", although the overload resolution happens in the compiler rather than in the runtime.

But note, however, that this overloading is also carefully hemmed in, because only overloads that are actually in scope at the time of the call will actually take effect. So again, the search space for finding overloads is less than global, and you only need look in header files and scopes that are visible to the calling site, which will typically be a small fraction of the total source code for an application.

So I hope that explains why overloading regular functions is perceived by some people to be of a different order than overloading class methods.

-- Talin



More information about the Python-3000 mailing list