[Python-3000] Fw: typeclasses, duck-typing
Phillip J. Eby
pje at telecommunity.com
Thu May 11 17:09:47 CEST 2006
At 10:12 AM 5/11/2006 +0100, Ben.Young at risk.sungard.com wrote:
>A dynamic version of concepts (I guess a combo of multi-methods and
>adaptation) would be great for Python, but it's hard to see how it could
>be done simply and efficiently.
Go back and read the post where I explained how, then. ;)
Seriously, it can be done as a pretty straightforward refactoring of
Guido's existing overloaded function implementation. You just need to be
able to pass in objects other than classes to define a signature.
But I suppose maybe it's one of those things that's only obvious and
straightforward to me, so I'll have to see if I can carve out some time
this weekend to implement a demo.
The harder problem is having a way to define overloaded methods that's at
least as convenient as 'def __iter__(self):' -- but that's a syntax issue.
It seems to me, however, that having something like a 'defop' keyword would
do the trick, if you also had argument types. So if you were implementing
UserList or UserDict, you could have some code like this in the class body:
defop len(self):
return len(self.data)
defop iter(self):
return iter(self.data)
defop operator.getitem(self, key):
return self.data[key]
The idea here is that defop takes an *expression* (actually just a dotted
name, like decorators) before the parentheses, that is the function to
overload, rather than the *name* that the defined function is to be bound
to. (i.e., the code above would need to have done an 'import operator' so
that operator.getitem is available)
Of course, this approach would give overloaded functions a much more
central place in things, and Guido's just said that's out, so this may be
moot. I'm only showing this example because I think getting rid of
__magic_names__ for operations could be a good thing for readability, and
it would remove an element of "magic" from today's Python.
The trickiest part of implementing this is that you have to implicitly use
the enclosing class as the signature type for the 'self' argument, which
could be a PITA to implement. RuleDispatch actually does this trick by
decorating the class on the fly and delaying the method addition until the
class is created, so it's certainly possible to do it, even without
language support.
Anyway, the idea is pretty much moot unless Guido becomes a lot more fond
of generic functions than he is currently -- i.e., fond enough to expend a
keyword on them, make all the __methods__ go away, and also implement his
type signature proposal. That *would* be a paradigm shift, albeit one that
I doubt many Python users would seriously object to.
For one thing, "defop iter" is two less keystrokes than "def __iter__" and
involves less use of the shift key. ;) For another, the idea of operator
overloading (hm, there's that word again) is pretty well established in
other languages, so it's easy to teach to experienced programmers and makes
Python seem more attractive.
Of course, it's slightly more keystrokes for operator.add and other
operations that aren't builtins. And we'd have to either add an
'operator.radd', or else do something like:
defop operator.add(self, other):
# code for adding an ob of this class to anything
defop operator.add(other:object, self:class):
# code to add something to this class
This assumes that you can use the 'class' keyword in an argument definition
to refer to the enclosing class; if you don't have that, then you would
have to do the definition outside the class in order to refer to it by name.
Anyway, I think that this is a paradigm shift that would actually increase
the language's beauty and clarity, because then the __magic__ names would
only be for *data*, like __file__, __name__, __class__, __dict__, etc.
To really make it work "all the way down", however, we'd have to implement
the builtin generic functions in such a way that they still use type slots
and magic attributes "under the hood", at least transitionally, because
there's all the C code that uses them and there would also be a performance
hit to doing a dictionary lookup whenever you want to use len() or iter(),
even at C level. So 'defop' would need to be defined in such a way that it
asks the generic function to register the implementation, and "builtin
generic functions" would do their registration by modifying the class's
tp_* slots.
And if both these "builtin" and "user" generic functions were able to be
queried by type, you could get access to type slot values without having to
expose them as gettable magic attribute names...
We would have to effectively add operator.next(), operator.enter() and
operator.exit() to get rid of most of the remaining magic names, but that's
not a big deal.
This is the first half of what I'd propose for such a paradigm shift; the
second half is specific to how the adaptation/typeclass stuff would work,
so I won't bother with explaining any of it unless Guido shows some
interest in this part; if he doesn't like the above, he's not going to be
convinced by how neat the solution for the rest is. ;)
More information about the Python-3000
mailing list