[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