Coerce and multimethods (was Re: Inefficiency of __getattr__)

Huaiyu Zhu hzhu at yahoo.com
Wed Oct 4 04:39:01 EDT 2000


On 03 Oct 2000 17:04:06 +0200, Martin von Loewis
<loewis at informatik.hu-berlin.de> wrote: 
>
>> Sometime ago there was a brief discussion of multimethods here.  The idea is
>> that a+b will be dependent on the classes/types of both a and b.  I did not
>> quite understand it at the time.  But now it looks to me like that
>> __coerce__ is simply an awkward way of doing it half-heartedly.
>
>Well, coercion is intended to do just that: coerce the arguments to a
>common type. In arithmethic operations, it is an elegant way to deal
>with the subset/superset problem. Since
>
>  Natural \subset Rational \subset Real \subset Complex
>
>it is straight-forward to assume that number-like objects support
>coercion.

Except that numerical objects are not always one-dimensional.  There are
many operations that depend on the types of both operands that can't be
handled by coersion.

>> In another thread yesterday someone suggested a three way coerce, using the
>> operation as a third argument to fine tune the coersion.  That would still
>> leave out the info about the original operands, though.  A multimethod would
>> solve all these in a much cleaner way.
>
>I don't understand. If you want to operate on the original operands,
>you don't need any coercion...

I'm developing the MatPy packge (see my sig) where matrices are implemented
as wrappers around Numeric.array objects.  So conceptually a+b is actually
Matrix(a.data+b.data), except that this would fail if either a or b is a
pure number.  So the actual implementation goes through a few hoops of
__add__, __radd__, __init__, and so on.  This adds an overhead that's
equivalent to adding two 100 element vectors.  This is a ten times slowdown
if you add two 20 element vectors.

Having coerce in the middle just made things worse. Since I added a
__getattr__ to make it possible to use a.T instead of a.T() for
transpose(a), there was an additional six fold slowdown for any binary
operation.  Now adding a __coerce__ that does nothing removes the extra cost
of __getattr__, but itself is still quite costly.

Now that I've encountered coerce unexpectedly, I'm thinking of whether it
could be put to any use.  However, it is not so, because it knows nothing
about the operand, nor the desired return type (which is not
a.data.__class__ but a.__class__).

If you can take a look at the codes maybe you can make some suggestions.
Currently with the do-nothing __coerce__ and some tuning the total overhead
is equivalent to adding two vectors of a couple dozen elements.

>
>> Short of that, maybe we should propose to use __coerce__ only for builin
>> (numeric) types and explicit coerce calls?  
>
>No, that would be a significant change, breaking compatibility.

Why, are there applications other than the built in numeric types that use
__coerce__?  If there are only a few known cases, it would quite easy to
require them to call coerce explicitly.

>
>> What are the most significant applications that use coerce, anyway?
>
>Numerical types, i.e. objects implementing __add__, __mul__, and so
>on.  If your type is not numerical, perhaps it should not provide an
>__add__?

It is numerical, but not limited to the simple builtin types.

>In any case, contributions to
>http://python.sourceforge.net/peps/pep-0208.html are welcome.

Yet another empty PEP?  

-- 
Huaiyu Zhu                       hzhu at users.sourceforge.net
Matrix for Python Project        http://MatPy.sourceforge.net 



More information about the Python-list mailing list