[Python-3000] pep 3124 plans

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