just to introduce me and some comments
Hello, since i am new to this group, ok, i'm Thomas. I've taken the CXX package 3 months ago (don't know which version it was) and changed many things to suit my needs. My requirements were: - simple, homogeneous look of my wrapper classes, since i had to write a whole lot of them - use of inheritance in the wrapper classes, since the class library i had to incorporate into python, had it, and i didn't want to do mass copies of source code (every base class method in every subclass) - the whole thing has to run rock solid, since it's going to be used for interconnecting stock trading applications in a financial institute. - I wanted to rely on C++ exceptions as error notification mechanism. What i did: I moved the inheritance of the PythonExtension template from PyObject 'one level up', by introducing an intermediate class CXXPyObject with a virtual destructor: // The purpose of this is only to get a virtual destructor into a PyObject and to // be able to use dynamic_cast on it. PythonExtension inherits virtually from this. class CXXPyObject : public PyObject { protected: CXXPyObject() {} public: virtual ~CXXPyObject() {} }; CXXObject is a virtual base class for PythonExtension. Now, i can use dynamic_cast even in situations, where i inherit from PythonExtension multiple times, see below. Another thing i changed was to eliminate the template argument from PythonType. It's only purpose was to get the Object size, but you can pass this easily as a constructor argument, or even pass the size as a template argument. The downside is, you have to keep PythonExtension as a template class, since the constructor cannot determine the object size at construction time. To do easy, safe casting in the static member functions (Python entry points) i introduced a template function T python_cast<class T>(PyObject *). This does first a static_cast to the CXXObject*, and then a dynamic_cast to the object i'm actually in. Of course, this does NOT lead me magically into the paths of the right member functions of the right class, but i'm using dynamic_cast & the virtual function table for type checking, which gives me a fairly efficient type safe conversion. template<class T> T python_cast(PyObject *p) { T result = dynamic_cast<T>(static_cast< CXXPyObject* >(p)); if (result == NULL) { cerr << "!shit! cast failed!" << endl; throw bad_cast(); } return result; } Lastly, i've added some 'standard' functionality into PythonType & PythonExtension, such as str(), repr(), getattr(). I strictly obey the following rule in my source: - Python entry points always have a name starting with 's_' (such as s_str(PyObject* self, PyObject* a) ) - the first lines look like MyClassName* self=python_cast<MyClassName*>(s); // looks damn familiar, doesn't it ? Tuple args(a); so, here's some chunk out of the PythonExtension template: // since CXXPyObject is a virtual Baseclass of PythonExtension, you can // safely use multiple inheritance with the following Scheme: // class A : public PythonExtension<A> { // }; // class B : public A, public PythonExtension<B> { // } // // in A's an B's methods you may use the python_cast<A*>() thing below // to get a A* or B* out of a PyObject * template<class T> class PythonExtension: public virtual CXXPyObject { private: static void extension_object_deallocator(PyObject* t) { CXXPyObject* o=static_cast<CXXPyObject*>(t); delete o; // delete t; } explicit PythonExtension(const PythonExtension<T>& other); void operator=(const PythonExtension<T>& rhs); protected: explicit PythonExtension() { ob_refcnt = 1; ob_type = type_object(); } public: virtual ~PythonExtension() {} static PythonType& behaviors() { static PythonType* p; if(!p) { p = new PythonType(sizeof(T)); p->dealloc(extension_object_deallocator); p->str(s_str); p->repr(s_repr); } ... } If someone's interested; i can send the whole story(code). BTW, I've also implemented some huge macros for easy (and safe!) use of exceptions within C++ Modules. Note that you CAN'T throw exceptions 'through' the python interpreter. Consider this: PyObject* mainEventLoop() { PyObject* o=someObject; try { while (...) // some crufty event magic going on if (eventOccured()) Py_CallMethod(o,"crashbang",...); } catch (const Exception&) { } } and 'crashbang()' calls a C++ method from within your module, which throws an exception. My experience was that the process will go wreck, with the default execption handler aborting the program. What i did is to write a macro to catch these exceptions and to return Null instead. Ok, that's it for today. Comments are welcome. Thomas Malik
Thanks for your work on CXX, since it sounds quite interesting. (I've attempted to use CXX in the past, and run into problems with the GNU compiler. I'm told these should be fixed by now.) Could you see how your version of CXX compares to the one just posted by Paul Dubois to cxx.sourceforge.net? I'd love to see us have a single version of CXX with the best ideas of everyone who has worked on it. I'd sure like to see your safe casting and other fixes incorporated into an "official" release. Are you by any chance willing to "adopt" CXX, since I understand Paul is not using C++ in his current job? -- Joe VanAndel National Center for Atmospheric Research http://www.atd.ucar.edu/~vanandel/ Internet: vanandel@ucar.edu
-----Ursprüngliche Nachricht----- Von: Joe Van Andel <vanandel@atd.ucar.edu> An: Thomas Malik <Thomas.Malik@t-online.de> Betreff: Re: [C++-SIG] just to introduce me and some comments [...}
Could you see how your version of CXX compares to the one just posted by Paul Dubois to cxx.sourceforge.net? I'd love to see us have a single version of CXX with the best ideas of everyone who has worked on it.
I'd sure like to see your safe casting and other fixes incorporated into an "official" release.
Are you by any chance willing to "adopt" CXX, since I understand Paul is not using C++ in his current job?
So, i do and will use the CXX package a lot, because it's what my current work is based upon. I like it very much, because i think it's the 'better' way to integrate C++ APIs into Python. I mean, if one extends the capabilities of a specific C++ API in a 'Python - compatible' manner, one can take advantage from both: the dynamic typing and ease of use from Python, and the efficiency and 'lower level' capabilities of C++. So, yes, i am going to look into the newest CXX version and see how i can integrate my changes into the 'baseline'. Mainly, what i did, was this 'python_cast' stuff, so that you are able to use inheritance and better type - safety, and a greater number of numeric conversions in the Int, Long & Float classes from CXX_Objects.h. The other things were this CATCH_ALL_EXCEPTIONS cpp Macro & a new Macro for Argument checking (which gives you more Python - conformant error messages). Thomas
I realise I'm late in answer your message... Can I assume that the current sources in SourceForge address all your issues with CXX. If not please let me know what is missing. I think your comments are on a version of CXX before I contributed code. Barry
-----Original Message----- From: c++-sig-admin@python.org [mailto:c++-sig-admin@python.org]On Behalf Of Thomas Malik Sent: 03 March 2000 23:53 To: c++-sig@python.org Subject: [C++-SIG] just to introduce me and some comments
Hello, since i am new to this group, ok, i'm Thomas. I've taken the CXX package 3 months ago (don't know which version it was) and changed many things to suit my needs. My requirements were: - simple, homogeneous look of my wrapper classes, since i had to write a whole lot of them - use of inheritance in the wrapper classes, since the class library i had to incorporate into python, had it, and i didn't want to do mass copies of source code (every base class method in every subclass) - the whole thing has to run rock solid, since it's going to be used for interconnecting stock trading applications in a financial institute. - I wanted to rely on C++ exceptions as error notification mechanism.
What i did: I moved the inheritance of the PythonExtension template from PyObject 'one level up', by introducing an intermediate class CXXPyObject with a virtual destructor:
// The purpose of this is only to get a virtual destructor into a PyObject and to // be able to use dynamic_cast on it. PythonExtension inherits virtually from this. class CXXPyObject : public PyObject { protected: CXXPyObject() {} public: virtual ~CXXPyObject() {} };
CXXObject is a virtual base class for PythonExtension. Now, i can use dynamic_cast even in situations, where i inherit from PythonExtension multiple times, see below. Another thing i changed was to eliminate the template argument from PythonType. It's only purpose was to get the Object size, but you can pass this easily as a constructor argument, or even pass the size as a template argument. The downside is, you have to keep PythonExtension as a template class, since the constructor cannot determine the object size at construction time.
To do easy, safe casting in the static member functions (Python entry points) i introduced a template function T python_cast<class T>(PyObject *). This does first a static_cast to the CXXObject*, and then a dynamic_cast to the object i'm actually in. Of course, this does NOT lead me magically into the paths of the right member functions of the right class, but i'm using dynamic_cast & the virtual function table for type checking, which gives me a fairly efficient type safe conversion.
template<class T> T python_cast(PyObject *p) { T result = dynamic_cast<T>(static_cast< CXXPyObject* >(p)); if (result == NULL) { cerr << "!shit! cast failed!" << endl; throw bad_cast(); } return result; }
Lastly, i've added some 'standard' functionality into PythonType & PythonExtension, such as str(), repr(), getattr(). I strictly obey the following rule in my source: - Python entry points always have a name starting with 's_' (such as s_str(PyObject* self, PyObject* a) ) - the first lines look like MyClassName* self=python_cast<MyClassName*>(s); // looks damn familiar, doesn't it ? Tuple args(a);
so, here's some chunk out of the PythonExtension template: // since CXXPyObject is a virtual Baseclass of PythonExtension, you can // safely use multiple inheritance with the following Scheme: // class A : public PythonExtension<A> { // }; // class B : public A, public PythonExtension<B> { // } // // in A's an B's methods you may use the python_cast<A*>() thing below // to get a A* or B* out of a PyObject * template<class T> class PythonExtension: public virtual CXXPyObject { private: static void extension_object_deallocator(PyObject* t) { CXXPyObject* o=static_cast<CXXPyObject*>(t); delete o; // delete t; }
explicit PythonExtension(const PythonExtension<T>& other); void operator=(const PythonExtension<T>& rhs); protected: explicit PythonExtension() { ob_refcnt = 1; ob_type = type_object(); } public: virtual ~PythonExtension() {}
static PythonType& behaviors() { static PythonType* p; if(!p) { p = new PythonType(sizeof(T)); p->dealloc(extension_object_deallocator); p->str(s_str); p->repr(s_repr); } ... }
If someone's interested; i can send the whole story(code). BTW, I've also implemented some huge macros for easy (and safe!) use of exceptions within C++ Modules. Note that you CAN'T throw exceptions 'through' the python interpreter. Consider this:
PyObject* mainEventLoop() { PyObject* o=someObject; try { while (...) // some crufty event magic going on if (eventOccured()) Py_CallMethod(o,"crashbang",...); } catch (const Exception&) { } }
and 'crashbang()' calls a C++ method from within your module, which throws an exception. My experience was that the process will go wreck, with the default execption handler aborting the program. What i did is to write a macro to catch these exceptions and to return Null instead.
Ok, that's it for today. Comments are welcome.
Thomas Malik
_______________________________________________ C++-SIG maillist - C++-SIG@python.org http://www.python.org/mailman/listinfo/c++-sig
participants (3)
-
Barry Scott -
Joe Van Andel -
Thomas.Malik@t-online.de