[C++-sig] Exposing boost::function

François Duranleau duranlef at iro.umontreal.ca
Mon May 15 19:57:44 CEST 2006


Hi all!

Last weekend, I though of a few things about exposing boost::function to 
Python and I would like to share those ideas and know what others think 
about it. This is also a kind of follow up to the thread 
http://thread.gmane.org/gmane.comp.python.c++/9062/focus=9101 .

Simply put, the problem is exposing something like:

template < Func >
void do_something( Func f ) { ... }

where Func is a function of some kind (conceptually).

The first step of the solution would be to actually expose this:

using namespace boost::python ;
typedef boost::function< the_appropriate_signature > function_type ;

def( "do_something" , & do_something< function_type > ) ;

but then (actually, before) when have to expose function_type. Suppose we 
do this:

class_< function_type >( "Function" )
     .def( "__call__" , & function_type::operator() )
     ;

and suppose we did something to create a Function from any callable 
object, then in Python, we would have to call do_something like, e.g.:

do_something( Function( callable_object ) )

In C++, there is an implicit conversion between functors and functions to 
boost::function, so it would be very nice to do the same in Python, e.g.:

do_something( callable_object )

Up to here we can ask ourselves: then is there any need to really expose 
boost::function?

This is where I worked a few things. At first I thought: well, no, since 
in Python there is no need for such a class (it has its own mechanisms to 
abstract callbacks), then boost::function should be completely 
transparent. That means when we return a boost::function in C++, we should 
extract its content to Python.

To avoid a very long message, I won't post the code here. You can find it 
there:
http://www-etud.iro.umontreal.ca/~duranlef/python/function.hpp 
http://www-etud.iro.umontreal.ca/~duranlef/python/function_test.cpp 
http://www-etud.iro.umontreal.ca/~duranlef/python/function_test.py
Read the comments.

It is to note that as much as we can, we could like to avoid calling back 
to Python when calling the operator() of a boost::function in C++ if it 
contains a C++ object exposed to Python. We can achieve this to a limited 
extend with boost::python::implicitly_convertible<>, as presented in the 
code above.

Now, there is a problem when a C++ function returns a boost::function, 
because its content might not be something exposed to Python, and as you 
can see in the code above (in function.hpp, the to_python converter), 
things can get ugly. This morning, I thought of another, simpler approach: 
expose boost::function "regularly", plus add some extra implicit 
converters to allow the above. This avoid the return problem, but we have 
an extra level of indirection when calling the "function" in Python.

The code for that version is here:
http://www-etud.iro.umontreal.ca/~duranlef/python/function_v2.hpp
http://www-etud.iro.umontreal.ca/~duranlef/python/function_test_v2.cpp
http://www-etud.iro.umontreal.ca/~duranlef/python/function_test_v2.py

There is a Jamfile (and Jamrules, both inspired by the Boost.Python 
tutorial) here to compile both version: 
http://www-etud.iro.umontreal.ca/~duranlef/python/Jamfile 
http://www-etud.iro.umontreal.ca/~duranlef/python/Jamrules

P.S.: the code is not complete and the way things are written is not 
necessarily the best way. It is mostly just a proof of concept.

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

"Like individual, like organization. Overspecialization leads to death."
                                 - Motoko Kusanagi, in _Ghost in the Shell_


More information about the Cplusplus-sig mailing list