[C++-sig] Interface design.

Ralf W. Grosse-Kunstleve rwgk at yahoo.com
Tue Apr 22 20:20:25 CEST 2003


Hi!

This is a very nice overview of component based development with Boost.Python!
I'd like to add one more great discovery (thanks to Dave):

It is easily possible to add member functions/methods from Python.
For example:

In C++:

    class_<point>("point") ... ;

Now in Python, e.g. in Bruno's __init__.py file:

# a regular function
def point_repr(self):
  return str((self.x, self.y))

# now we turn it into a member function
point.__repr__ = point_repr

*All* point instances created from C++ will have this pure-Python
member function!

We use this trick to:

  - keep all I/O related code out of our C++ libraries (no trouble with
    redirecting)
  - cut down compile times to zero for these additional functions
  - reduce the memory footprint to virtually zero
  - minimize the need to recompile
  - rapid prototyping (you can move the code to C++ if required without
    changing the interface)
  - have less source code

Another useful idea is to replace constructors with factory functions:

_point = point

def point(x=0, y=0):
  return _point(x, y)

In this simple case there is not much gained, but for constructurs with
many overloads and/or arguments this is often a great simplification, again
with virtually zero memory footprint and zero compile-time overhead for
the keyword support.

Ralf

--- Nicodemus <nicodemus at globalite.com.br> wrote:
> Hi!
> 
> Suppose you want to have a top level package in python named kikura, 
> with two sub-modules, core and node, so that a user uses your package 
> like this:
> 
>     import kikura.core
>     import kikura.node
>     kikura.core.Foo()
> 
> 
> You can acomplish this generating the two sub-modules (core and node) 
> using Boost.Python, like any other module:
> 
>     // file core.cpp
>     BOOST_PYTHON_MODULE(core)
>     {
>        ...
>     }
> 
>     // file node.cpp
>     BOOST_PYTHON_MODULE(node)
>     {
>        ...
>     }
> 
>     And creating the following directory structure:
> 
>     /kikura
>         __init__.py 
>         core.pyd
>         node.pyd
> 
> 
> And that's it (the file __init__.py indicates that the directory is a 
> package. It can be empty, but it can be useful to provide a more 
> friendly interface for your users. See below).
> 
> I suggest that you name your bindings _core and _node, thought, and make 
> the sub-modules *python* modules which import the funcionality of the 
> bindings, like so:
> 
>     /kikura
>         __init__.py
>         /core
>             __init__.py
>             _core.pyd
>         /node
>             __init__.py
>             _node.pyd
> 
> 
> with /kikura/core/__init__.py contains the statement "from _core import 
> *". The same for the node package. Why do it like this? Well, because 
> then you can easily implement some things in python in a way that is 
> transparent for the user (I am assuming here that you're developing this 
> library). Suppose you want to add a new utility function into the core 
> package, made in python. You just create a file "foo.py" and put it 
> inside /kikura/core, and add this line to its __init__.py:
> 
>     from foo import util_function, other_function
> 
> 
> and your users will access it like so:
> 
>     import kikura.core
>     kikura.core.util_function(10)
> 
> 
> Back to the compilation time issue, notice that you don't have to write 
> all class_ declarations inside the BOOST_PYTHON_MODULE macro directly, 
> you can split them in any number of files you like. For example:
> 
>     // file Foo.cpp
>     #include <kikura/Foo.h>
>     void export_foo()
>     {
>         class_<Foo>()...
>     }
> 
>     // file Bar.cpp
>     #include <kikura/Bar.h>
>     void export_bar()
>     {
>         class_<Bar>()...
>     }
> 
>     // file core.cpp
>     void export_foo();
>     void export_bar();
>     BOOST_PYTHON_MODULE(core)
>     {
>         export_foo();
>         export_bar();
>     }
> 
> 
> This will take longer to compile than a single file (because the 
> Boost.Python headers must be compiled for each cpp), but if your 
> developing the library this is a big help, because a change in a header 
> doesn't mean the entire bindings will have to be recompiled.
> 
> Hope that helps,
> Nicodemus.


__________________________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo
http://search.yahoo.com




More information about the Cplusplus-sig mailing list