[Python-3000] defop ?
Talin
talin at acm.org
Thu Nov 23 09:35:02 CET 2006
Guido van Rossum wrote:
> On 11/22/06, Calvin Spealman <ironfroggy at gmail.com> wrote:
>> This whole thing seems a bit off from start to finish. A seperate
>> definition syntax with a special name/expression weirdo thingy, etc.
>
> I have the same gut feelings but find it hard to explain why.
>
> But I've learned to trust my gut -- eventually it will come to me.
Here's my understanding of the rationale for defop:
From an implementation standpoint, everything that defop does can be
emulated by an appropriate set of function decorators. However, when we
start getting into things like namespaces and operators, some of those
decorators start to look pretty ugly and have unwanted side-effects.
If all we wanted to do was to be able to create generic functions in the
global namespace, the decorator syntax could be fairly simple:
@overload
def len( x : list ):
...
The decorator can inspect the function object to discover the name of
the function - so there's no need to pass a separate argument to the
decorator telling it what function to overload:
@overload( len )
def len( x : list ):
...
This syntax is less desirable since it violates DRY.
In either case, what the decorator returns is not the reference to the
function object, but rather the reference to the generic dispatcher
object, 'len'. The result of the decorator will then be bound to the
name 'len' in that scope.
(It means that for every overload, the name 'len' gets rebound to the
same dispatcher object over and over.)
Now, all that's fine and dandy as long as we limit ourselves to only
creating global functions with names that conform to the syntax of
Python identifiers.
But what if we don't want to clutter up the global namespace? Suppose we
want to create a generic function in some other namespace, such as an
attribute of an object. Now in order to define the overload, we have to
do something like this:
@overload( sequtils.len )
def len( x : list ):
...
The problem here is that the function object is going to get bound to
the name 'len' no matter what - the decorator can't control that. Even
if we go ahead and add the function object as a method of
'sequtils.len', we still, as a side-effect, end up binding the result of
the decorator to 'len', which will at best create a spurious symbol, and
at worse overwrite something we actually wanted to keep.
Taking this one step further, suppose we wanted to get rid of the
__special__ names for overloaded operators, and instead be able to use
the actual symbol for the operator. Suppose there was a built-in
dictionary of operators, where the keys of this dictionary was the
actual operators themselves. So 'infix['+']' would be the expression for
the generic infix addition operator.
You could easily create a decorator that takes the operator name as an
argumemt, similar to @overload above:
@overload_infix('+')
def add_bool_to_bool( a : bool, b : bool ):
...
But again, you have to deal with the unwanted function name. And you
can't embed the '+' symbol in the function name itself, since '+' isn't
allowed in Python identifiers.
(Maybe not the best of examples, but it illustrates the idea that
perhaps not all generic functions will have simple names.)
Now, if we had anonymous functions (hint, hint :) ) we could say
something along the lines of:
infix( '+' ) += def( a : bool, b: bool ):
...
(Not the prettiest syntax I know...but at least it gets around the
'tyranny of naming')
I suppose you could do that with lambda now, if your implementation was
limited to a single expression with no statements (although that's a
question - will lambda support decorated arguments?)
So my understanding is that 'defop' is a way to get around all of these
issues. 'defop' is nothing more than 'def', except that it has a
different rule as to how the function object is bound to a name.
(PJE, do I have this right?)
All that being said - I'm not sure that 'defop' is the right name for
it, or that it's even the right way to solve it. But I hope that my
explanation (if it's correct) may help clear up the discussion a bit.
-- Talin
More information about the Python-3000
mailing list