[Python-3000] Fw: typeclasses, duck-typing
Phillip J. Eby
pje at telecommunity.com
Thu May 11 18:18:39 CEST 2006
At 04:27 PM 5/11/2006 +0100, Ben.Young at risk.sungard.com wrote:
>Why not
>
>class Foo(object):
> @specialize(arg(0))
> def core.len(self)
> ...
Where does 'core' come from? What is specialize for? I don't understand
what you're proposing.
>I don't know how this would appear in the class dict though? self.len()?
In my proposal, 'defop' doesn't bind anything; it's just a statement that
defines a function object and then adds that function to the specified
overloaded function. If it occurs in a class body, the function would be
*defined* where it is, but it would not be added to the targeted operation
until after the class was created.
Doing the actual overloading would be accomplished by an "overload()"
generic function, meaning that users could define their own generic
function implementations and use them with 'defop'. Decorated defops would
apply the decorators to the function before doing the overload, so a
RuleDispatch implementation for Py3K might use something like this to add a
predicate:
@when("something(arg1) and arg2>arg3")
defop foo.bar(arg1, arg2:int, arg3:int):
# blah blah
This assumes that 'foo.bar' is a RuleDispatchGenericFunction, and something
like this has been defined:
class RuleDispatchGenericFunction:
# ...
defop operator.overload(self, function):
# code to extract type signature from provided function
# along with an optional predicate tacked on by @when,
# and then register it using RuleDispatch's indexing
# system
In other words, I'm saying that 'defop' is equivalent to having a decorator
that calls 'operator.overload(generic, function, cls)', and also throws
away the function instead of binding it to a name. (cls here is either the
class
So by making the overload() function a generic function, we can have
multiple implementations of generic functions. Anybody can experiment with
custom approaches to overloading implementations, but they can all use a
common syntax (defop) to work. The overload implementation for builtin
generic functions like len() and iter() would be something like this (if it
were expressed in Python rather than C):
defop operator.overload(gf:BuiltinGenericType, function):
# code to put function in the appropriate tp_* slot of the
# declared type of the function's first argument, using
# info from 'gf' to know which slot to use
So builtin generic functions like iter() and len() would be
BuiltinGenericType instances, that have information that indicates what
tp_* slot they use and what kind of C wrapper is required. The tp_call of
BuiltinGenericType would then just do a slot lookup for the desired
thing. So we end up right where we are now in terms of performance for
these operations, because they work the same as they always did. It's just
that we can drop having __magic__ names for them.
In fact, we don't even change the existing C APIs that implement these
"generic" functions; all we're really doing is splitting up the existing
setattr/dict->tp_* slot machinery into a set of data structures to be
driven by a single basic approach.
In other words, we're just creating a uniform way to register methods with
generic functions, that just happens to have a special fast path for
language-defined operations.
The most "interesting" part is likely to be the resolution of binary
overloads for existing __add__ vs. __radd__ stuff, both in how best to
spell such definitions in code, and in how the builtin generics would
implement dispatching.
More information about the Python-3000
mailing list