[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