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

François Duranleau duranlef at iro.umontreal.ca
Wed Jan 18 21:09:51 CET 2006


On Wed, 18 Jan 2006, mathieu lacage wrote:

> hi,
>
> François Duranleau wrote:
>
>>  with C++ name patterns. As a matter of fact, we could also use a hack
>> with the __class__ attribute (it seems like the value for all
>> Boost.Python classes is <type 'Boost.Python.class'>. But what about
>> C++ functions? Are we
>
>
> What would such a hack do ? Recognize which classes are exported by
> boost.python and are thus C++ bound classes ? What would you use this for ?

It could be used like this:

def make_callback( obj ) :
     if repr( obj.__class__.__class__ ) \
        == "<type 'Boost.Python.class'>" :
         return obj
     else :
         return convert_python_object_to_boost_function( obj )

This solves some of the problems with the approach I suggested using 
boost::function (uniformity). I don't like it much more than the name 
pattern approach though, especially because if the name of the type ever 
changes, it breaks down. Also, to deal with C++ functions, we still have 
to define some wrapper functors in C++.

Actually, it is not so hard to write some helpers to make this easier 
(wrapping functions). I have updated my example with the use of 
make_callback as above and I added some helpers. Everything is still at:

http://www-etud.iro.umontreal.ca/~duranlef/python/

All that being said, coming back to the hack, in a case like your callback 
framework, I don't think it can be very useful. Your approach has the 
advantage of dealing directly with the non-wrapped function/functor, and 
the hack (__class__ attribute) is not very useful in selecting and 
instantiating the desired callback wrapper (at least, I don't see how 
either).

Now coming back to your framework, you said at some point that the process 
could be helped with templates for exporting function wrappers. Well, I 
think you could use a pattern similar to the helper I wrote in my new 
example. Here is how (not tested):

template < typename Function ,
            typename Tag >
struct function_wrapper_callback
     : Callback1
{
     static Function func ;

     void operator () ( int a )
     {
         func( a ) ;
     }
} ;

template < typename Function ,
            typename Tag >
Function function_wrapper< Function , Tag >::func = Function() ;

template < typename Tag ,
            typename Function >
void
export_function_callback( Function f ,
                           const char* name )
{
     typedef function_wrapper_callback< Function , Tab > callback_type ;

     // Ensures unicity of callback_type for f
     assert( callback_type::func == Function() ) ;

     callback_type::func = f ;

     class_< callback_type ,
             bases< Callback1 > ,
             boost::noncopyable >( name ) ;
}


And in the module section, taking your example of function 
'real_function', you could export it like this:

// declare the tag ouside of BOOST_PYTHON_MODULE(...)
struct real_function_tag ;

export_function_callback< real_function_tag >( & real_function ,
                                                "real_function_callback" );

This also should work out of the box with stateless functors.

You can do something similar with methods by adding a member 'self' in the 
wrapper (pointer to the object), a constructor with the object to bind to 
the method as an argument, and calling the method with ->. in operator(). 
Actually, I think you could even have a single wrapper for both functions 
and method using boost::function and boost::bind.

-- 
François Duranleau
LIGUM, Université de Montréal

"All wealth is created by human beings using their neurons intelligently."
                           - Robert Anton Wilson, _Prometheus Rising_, 1983


More information about the Cplusplus-sig mailing list