Polymorphism and wrapping Python

Daniel Keep daniel.keep.lists at gmail.com
Sat Jun 3 02:44:35 PDT 2006



Kirk McDonald wrote:
> I'm currently writing a family of classes that wrap the object layers of
> the Python/C API. The class hierarchy looks something like this:
> 
> DPyObject
>   DPyNumber
>     DPyInteger
>     DPyFloat
>     (etc)
>   DPySequence
>     DPyString
>     DPyList
>     (etc)
>   DPyMapping
>     DPyDict
>   (etc)
> 
> All of the classes on the second level are declared as "abstract," and
> (appropriately) represent the Python/C API's abstract objects layer.
> DPyObject and the classes on the third level are not abstract and
> represent the concrete objects layer. (Though I think I may eventually
> make DPyObject abstract, too.)
> 
> Behind this is a factory function that takes a PyObject* (the Python/C
> API's usual way of representing a Python object) and returns a instance
> of the proper subclass of DPyObject.
> 
> I have a question, then, of polymorphism, and how closely I should try
> to emulate Python.
> 
> In Python, if you try to (for example) add two instances of a class that
> doesn't have the __add__ method (Python's equivalent of opAdd) defined,
> Python will raise a TypeError. If you try to do this in D, it is a
> compile-time error.
> 
> At the moment, DPyObject doesn't define opAdd. DPyNumber does, like this:
> 
> DPyNumber opAdd(DPyNumber rhs) {
>     return make_dpyobject(PyNumber_Add(m_ptr, rhs.m_ptr));
> }
> 
> (If you're unfamiliar with the Python/C API, PyNumber_Add takes two
> PyObject* arguments and returns a new PyObject* with the result. m_ptr
> is the only member of DPyObject, and is a PyObject*. make_dpyobject is
> my factory function that returns the proper subclass of DPyObject based
> on the type of the PyObject* passed to it.)
> 
> If we have:
> 
> DPyObject o = new DPyInteger(5);
> DPyObject p = new DPyInteger(10);
> DPyObject q = o + p; // Error! DPyObject doesn't define opAdd.
> 
> I'm trying to decide if this is a problem. I can easily define this for
> DPyObject:
> 
> DPyObject opAdd(DPyObject rhs) { assert(false); }
> 
> Then the above example would work, but I'm not totally sure that this is
> desirable behavior. In Python it certainly would be: that language is
> all about the duck typing. It would certainly simplify the API, in that
> all DPyObject-derived classes would have the same interface (now there's
> an idea, I should write an interface...). But I still have this
> irrational fear that it is a bad idea.
> 
> Anyone have more insight than I can currently muster?
> 
> -Kirk McDonald

If I remember correctly, there are a bunch of fields that may or may not
actually be implemented for a particular PyObject.  Things like __add__,
__str__, __repr__, etc.  I personally think that all of these should be
on DPyObject, just with a default "blarg, I dies!" implementation.

That way, the D binding operates in approximately the same fashion as
Python itself.

The only thing I think would be different is that if, say, __add__
fails, then Python tries __radd__.  If I understand rightly, D does the
same thing... except at compile time.  Perhaps DPyObject should define a
general-purpose opXXX that first tries the operand's __xxx__ method,
then it's __rxxx__ method.

In any case, good to know you've gotten so far :)

	-- Daniel

-- 
Unlike Knuth, I have neither proven or tried the above; it may not even
make sense.

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D
i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/



More information about the Digitalmars-d mailing list