[C++-sig] optimizing away calls to the python runtime -- was [detecting if a function is written in python or C++]

David Abrahams dave at boost-consulting.com
Fri Jan 13 03:51:32 CET 2006


Mathieu Lacage <Mathieu.Lacage at sophia.inria.fr> writes:

> hi,
>
> I apologize for this second email but the more I think about what I am
> trying to do, the less I see how to do it. So, here is a hopefully
> detailed explanation of what I am trying to achieve.
>
> Here are my c++ classes:
> class Event {
> virtual void notify (void) = 0;
> };
> class Simulator {
>  void schedule (Event *event);
>  double now_s (void); // return current time.
>  void run (void);
> };
>
> sample c++ use code:
> class MyEvent : public Event {
> virtual void notify (void) {
> 	std::cout << "now=" Simulator::now_s () << std::endl;
> 	delete this;
> }
> };
>
> Simulator->schedule (new MyEvent ());
> Simulator->run (); // invokes MyEvent::notify sometime later.
>
> This sort of code requires a lot of "forwarding code". That is, you
> often have to write a bunch of Event-deriving classes whose sole purpose
> in life is to forward the call to their notify method to a call to
> another class' method with event-specific parameters. So, I have a small
> make_event c++ template which can be used to do this sort of thing:
>
> class MyClass {
> void random_stuff (double id) {
> 	std::cout << "id="<<id<<"now=" Simulator::now_s () << std::endl;
> }
> };
>
> MyClass *obj = new MyClass ();
>
> Simulator->schedule (make_event (&MyClass::random_stuff, obj, 10.0));
> Simulator->run ();
>
> Okay, so, to wrap this, I wrapped my Simulator class and my EventWrap
> class:
> struct EventWrap : yans::Event
> {
>         EventWrap( PyObject* self_);
>         virtual ~EventWrap();
>         virtual void notify (void);
> private:
>         PyObject *m_self;
> };
> EventWrap::EventWrap (PyObject* self_)
>         : m_self(self_)
> {
>         Py_INCREF(m_self);
> }
> EventWrap::~EventWrap()
> {
>         Py_DECREF(m_self);
> }

This causes a double deletion.  Also, the Py_INCREF is somewhat evil
for other reasons.  In the Boost.Python object model, C++ objects are
owned by their Python wrappers, not vice-versa.  I think you'd be a
lot better off if you stopped trafficking in raw pointers and used
boost::shared_ptr<Event> instead.

> void
> EventWrap::notify (void)
> {
>         call_method<void>(m_self, "notify");

If this is related to your subject line, you should know that this
sort of old-style polymorphism does incur needless calls into Python.
Use derivation from boost::python::wrapper<Event> instead, with
get_override().

>         delete this;

There's that double-deletion again.

> }
>
> namespace boost { namespace python {
>         template <>
>         struct has_back_reference<EventWrap>
>                 : mpl::true_ {};
> }}
>
> void
> export_event (void)
> {
>         class_<EventWrap, std::auto_ptr<EventWrap>, boost::noncopyable> event ("Event");
>         event.def ("notify", pure_virtual(&Event::notify));
> }
>
> void
> simu_insert_in_s (double delta, std::auto_ptr<EventWrap> ev)
> {
>         Simulator::insert_in_s (delta, ev.get ());
>         ev.release ();
> }
>
> void
> export_simulator (void)
> {
> 	def ("run", Simulator::run);
>         def ("insert_in_s", simu_insert_in_s);
> }
>
>
> which allows me to write the following python code:
> class __MyEvent__(Event):

Bad idea to name your symbols that way; __XXX__ symbols are by
convention reserved to the Python language.

>     def set_callback (self, function, *args):
>         self.__function_ = function;
>         self.__args_ = args;
>     def notify (self):
>         self.__function_ (*self.__args_);
>
> def make_event(function, *args):
>     ev = __MyEvent__ ();
>     ev.set_callback (function, *args);
>     return ev
>
> def my_nothing0 ():
>     print "my model now=%f" % simulator.now_s ();
> simulator.insert_in_s (4.0, make_event (my_nothing1, 99));
> simulator.run ()
>
>
> okay, so all of this stuff works really nicely but there is a catch. I
> would like to be able to write code such as:
>
> simulator.insert_in_s (4.0, make_event (simulator.now_s));
> simulator.run ()
>
> and ensure that once simulator.run has reached the Simulator::run c++
> method, no python code will be executed ever. Namely, I want call to
> make_event to generate a nice C++ Event class which will not call back
> into python's __MyEvent__.notify before calling simulator.now_s and
> Simulator::now_s. i.e., it should call back Simulator::now_s directly.
> 
> The more I think about this, the less I see a way to do this with boost.
> Have I missed something ?

Use new-style polymorphism.

HTH,

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com




More information about the Cplusplus-sig mailing list