summaryrefslogtreecommitdiff
path: root/libs/python/doc/PyConDC_2003
diff options
context:
space:
mode:
Diffstat (limited to 'libs/python/doc/PyConDC_2003')
-rw-r--r--libs/python/doc/PyConDC_2003/bpl.html22
-rw-r--r--libs/python/doc/PyConDC_2003/bpl.pdfbin0 -> 7316 bytes
-rw-r--r--libs/python/doc/PyConDC_2003/bpl.txt5
-rw-r--r--libs/python/doc/PyConDC_2003/bpl_mods.txt911
-rw-r--r--libs/python/doc/PyConDC_2003/default.css188
-rw-r--r--libs/python/doc/PyConDC_2003/python_cpp_mix.jpgbin0 -> 22831 bytes
-rw-r--r--libs/python/doc/PyConDC_2003/python_cpp_mix.pngbin0 -> 6293 bytes
7 files changed, 1126 insertions, 0 deletions
diff --git a/libs/python/doc/PyConDC_2003/bpl.html b/libs/python/doc/PyConDC_2003/bpl.html
new file mode 100644
index 000000000..32b655bd9
--- /dev/null
+++ b/libs/python/doc/PyConDC_2003/bpl.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
+
+<!-- Copyright David Abrahams 2006. Distributed under the Boost -->
+<!-- Software License, Version 1.0. (See accompanying -->
+<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
+<!-- Copyright David Abrahams 2006. Distributed under the Boost -->
+<!-- Software License, Version 1.0. (See accompanying -->
+<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
+<html>
+ <head>
+ <meta name="generator" content=
+ "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
+ <meta http-equiv="refresh" content="0; URL=http://www.boost-consulting.com/writing/bpl.html">
+
+ <title>Loading: &ldquo;Building Hybrid Systems With Boost.Python&rdquo;</title>
+ </head>
+
+ <body>
+ Loading...; if nothing happens, please go to <a href= "http://www.boost-consulting.com/writing/bpl.html">http://www.boost-consulting.com/writing/bpl.html</a>.
+ </body>
+</html>
+
diff --git a/libs/python/doc/PyConDC_2003/bpl.pdf b/libs/python/doc/PyConDC_2003/bpl.pdf
new file mode 100644
index 000000000..09827aff0
--- /dev/null
+++ b/libs/python/doc/PyConDC_2003/bpl.pdf
Binary files differ
diff --git a/libs/python/doc/PyConDC_2003/bpl.txt b/libs/python/doc/PyConDC_2003/bpl.txt
new file mode 100644
index 000000000..d6921b124
--- /dev/null
+++ b/libs/python/doc/PyConDC_2003/bpl.txt
@@ -0,0 +1,5 @@
+.. Copyright David Abrahams 2006. Distributed under the Boost
+.. Software License, Version 1.0. (See accompanying
+.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+This file has been moved to http://www.boost-consulting.com/writing/bpl.txt.
diff --git a/libs/python/doc/PyConDC_2003/bpl_mods.txt b/libs/python/doc/PyConDC_2003/bpl_mods.txt
new file mode 100644
index 000000000..d42f00f8b
--- /dev/null
+++ b/libs/python/doc/PyConDC_2003/bpl_mods.txt
@@ -0,0 +1,911 @@
+Copyright David Abrahams 2006. Distributed under the Boost
+Software License, Version 1.0. (See accompanying
+file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+.. This is a comment. Note how any initial comments are moved by
+ transforms to after the document title, subtitle, and docinfo.
+
+.. Need intro and conclusion
+.. Exposing classes
+ .. Constructors
+ .. Overloading
+ .. Properties and data members
+ .. Inheritance
+ .. Operators and Special Functions
+ .. Virtual Functions
+.. Call Policies
+
+++++++++++++++++++++++++++++++++++++++++++++++
+ Introducing Boost.Python (Extended Abstract)
+++++++++++++++++++++++++++++++++++++++++++++++
+
+
+.. bibliographic fields (which also require a transform):
+
+:Author: David Abrahams
+:Address: 45 Walnut Street
+ Somerville, MA 02143
+:Contact: dave@boost-consulting.com
+:organization: `Boost Consulting`_
+:status: This is a "work in progress"
+:version: 1
+:copyright: Copyright David Abrahams 2002. All rights reserved
+
+:Dedication:
+
+ For my girlfriend, wife, and partner Luann
+
+:abstract:
+
+ This paper describes the Boost.Python library, a system for
+ C++/Python interoperability.
+
+.. meta::
+ :keywords: Boost,python,Boost.Python,C++
+ :description lang=en: C++/Python interoperability with Boost.Python
+
+.. contents:: Table of Contents
+.. section-numbering::
+
+
+.. _`Boost Consulting`: http://www.boost-consulting.com
+
+==============
+ Introduction
+==============
+
+Python and C++ are in many ways as different as two languages could
+be: while C++ is usually compiled to machine-code, Python is
+interpreted. Python's dynamic type system is often cited as the
+foundation of its flexibility, while in C++ static typing is the
+cornerstone of its efficiency. C++ has an intricate and difficult
+meta-language to support compile-time polymorphism, while Python is
+a uniform language with convenient runtime polymorphism.
+
+Yet for many programmers, these very differences mean that Python and
+C++ complement one another perfectly. Performance bottlenecks in
+Python programs can be rewritten in C++ for maximal speed, and
+authors of powerful C++ libraries choose Python as a middleware
+language for its flexible system integration capabilities.
+Furthermore, the surface differences mask some strong similarities:
+
+* 'C'-family control structures (if, while, for...)
+
+* Support for object-orientation, functional programming, and generic
+ programming (these are both *multi-paradigm* programming languages.)
+
+* Comprehensive operator overloading facilities, recognizing the
+ importance of syntactic variability for readability and
+ expressivity.
+
+* High-level concepts such as collections and iterators.
+
+* High-level encapsulation facilities (C++: namespaces, Python: modules)
+ to support the design of re-usable libraries.
+
+* Exception-handling for effective management of error conditions.
+
+* C++ idioms in common use, such as handle/body classes and
+ reference-counted smart pointers mirror Python reference semantics.
+
+Python provides a rich 'C' API for writers of 'C' extension modules.
+Unfortunately, using this API directly for exposing C++ type and
+function interfaces to Python is much more tedious than it should be.
+This is mainly due to the limitations of the 'C' language. Compared to
+C++ and Python, 'C' has only very rudimentary abstraction facilities.
+Support for exception-handling is completely missing. One important
+undesirable consequence is that 'C' extension module writers are
+required to manually manage Python reference counts. Another unpleasant
+consequence is a very high degree of repetition of similar code in 'C'
+extension modules. Of course highly redundant code does not only cause
+frustration for the module writer, but is also very difficult to
+maintain.
+
+The limitations of the 'C' API have lead to the development of a
+variety of wrapping systems. SWIG_ is probably the most popular package
+for the integration of C/C++ and Python. A more recent development is
+the SIP_ package, which is specifically designed for interfacing Python
+with the Qt_ graphical user interface library. Both SWIG and SIP
+introduce a new specialized language for defining the inter-language
+bindings. Of course being able to use a specialized language has
+advantages, but having to deal with three different languages (Python,
+C/C++ and the interface language) also introduces practical and mental
+difficulties. The CXX_ package demonstrates an interesting alternative.
+It shows that at least some parts of Python's 'C' API can be wrapped
+and presented through a much more user-friendly C++ interface. However,
+unlike SWIG and SIP, CXX does not include support for wrapping C++
+classes as new Python types. CXX is also no longer actively developed.
+
+In some respects Boost.Python combines ideas from SWIG and SIP with
+ideas from CXX. Like SWIG and SIP, Boost.Python is a system for
+wrapping C++ classes as new Python "built-in" types, and C/C++
+functions as Python functions. Like CXX, Boost.Python presents Python's
+'C' API through a C++ interface. Boost.Python goes beyond the scope of
+other systems with the unique support for C++ virtual functions that
+are overrideable in Python, support for organizing extensions as Python
+packages with a central registry for inter-language type conversions,
+and a convenient mechanism for tying into Python's serialization engine
+(pickle). Importantly, all this is achieved without introducing a new
+syntax. Boost.Python leverages the power of C++ meta-programming
+techniques to introspect about the C++ type system, and presents a
+simple, IDL-like C++ interface for exposing C/C++ code in extension
+modules. Boost.Python is a pure C++ library, the inter-language
+bindings are defined in pure C++, and other than a C++ compiler only
+Python itself is required to get started with Boost.Python. Last but
+not least, Boost.Python is an unrestricted open source library. There
+are no strings attached even for commercial applications.
+
+.. _SWIG: http://www.swig.org/
+.. _SIP: http://www.riverbankcomputing.co.uk/sip/index.php
+.. _Qt: http://www.trolltech.com/
+.. _CXX: http://cxx.sourceforge.net/
+
+===========================
+ Boost.Python Design Goals
+===========================
+
+The primary goal of Boost.Python is to allow users to expose C++
+classes and functions to Python using nothing more than a C++
+compiler. In broad strokes, the user experience should be one of
+directly manipulating C++ objects from Python.
+
+However, it's also important not to translate all interfaces *too*
+literally: the idioms of each language must be respected. For
+example, though C++ and Python both have an iterator concept, they are
+expressed very differently. Boost.Python has to be able to bridge the
+interface gap.
+
+It must be possible to insulate Python users from crashes resulting
+from trivial misuses of C++ interfaces, such as accessing
+already-deleted objects. By the same token the library should
+insulate C++ users from low-level Python 'C' API, replacing
+error-prone 'C' interfaces like manual reference-count management and
+raw ``PyObject`` pointers with more-robust alternatives.
+
+Support for component-based development is crucial, so that C++ types
+exposed in one extension module can be passed to functions exposed in
+another without loss of crucial information like C++ inheritance
+relationships.
+
+Finally, all wrapping must be *non-intrusive*, without modifying or
+even seeing the original C++ source code. Existing C++ libraries have
+to be wrappable by third parties who only have access to header files
+and binaries.
+
+==========================
+ Hello Boost.Python World
+==========================
+
+And now for a preview of Boost.Python, and how it improves on the raw
+facilities offered by Python. Here's a function we might want to
+expose::
+
+ char const* greet(unsigned x)
+ {
+ static char const* const msgs[] = { "hello", "Boost.Python", "world!" };
+
+ if (x > 2)
+ throw std::range_error("greet: index out of range");
+
+ return msgs[x];
+ }
+
+To wrap this function in standard C++ using the Python 'C' API, we'd
+need something like this::
+
+ extern "C" // all Python interactions use 'C' linkage and calling convention
+ {
+ // Wrapper to handle argument/result conversion and checking
+ PyObject* greet_wrap(PyObject* args, PyObject * keywords)
+ {
+ int x;
+ if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments
+ {
+ char const* result = greet(x); // invoke wrapped function
+ return PyString_FromString(result); // convert result to Python
+ }
+ return 0; // error occurred
+ }
+
+ // Table of wrapped functions to be exposed by the module
+ static PyMethodDef methods[] = {
+ { "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" }
+ , { NULL, NULL, 0, NULL } // sentinel
+ };
+
+ // module initialization function
+ DL_EXPORT init_hello()
+ {
+ (void) Py_InitModule("hello", methods); // add the methods to the module
+ }
+ }
+
+Now here's the wrapping code we'd use to expose it with Boost.Python::
+
+ #include <boost/python.hpp>
+ using namespace boost::python;
+ BOOST_PYTHON_MODULE(hello)
+ {
+ def("greet", greet, "return one of 3 parts of a greeting");
+ }
+
+and here it is in action::
+
+ >>> import hello
+ >>> for x in range(3):
+ ... print hello.greet(x)
+ ...
+ hello
+ Boost.Python
+ world!
+
+Aside from the fact that the 'C' API version is much more verbose than
+the BPL one, it's worth noting that it doesn't handle a few things
+correctly:
+
+* The original function accepts an unsigned integer, and the Python
+ 'C' API only gives us a way of extracting signed integers. The
+ Boost.Python version will raise a Python exception if we try to pass
+ a negative number to ``hello.greet``, but the other one will proceed
+ to do whatever the C++ implementation does when converting an
+ negative integer to unsigned (usually wrapping to some very large
+ number), and pass the incorrect translation on to the wrapped
+ function.
+
+* That brings us to the second problem: if the C++ ``greet()``
+ function is called with a number greater than 2, it will throw an
+ exception. Typically, if a C++ exception propagates across the
+ boundary with code generated by a 'C' compiler, it will cause a
+ crash. As you can see in the first version, there's no C++
+ scaffolding there to prevent this from happening. Functions wrapped
+ by Boost.Python automatically include an exception-handling layer
+ which protects Python users by translating unhandled C++ exceptions
+ into a corresponding Python exception.
+
+* A slightly more-subtle limitation is that the argument conversion
+ used in the Python 'C' API case can only get that integer ``x`` in
+ *one way*. PyArg_ParseTuple can't convert Python ``long`` objects
+ (arbitrary-precision integers) which happen to fit in an ``unsigned
+ int`` but not in a ``signed long``, nor will it ever handle a
+ wrapped C++ class with a user-defined implicit ``operator unsigned
+ int()`` conversion. The BPL's dynamic type conversion registry
+ allows users to add arbitrary conversion methods.
+
+==================
+ Library Overview
+==================
+
+This section outlines some of the library's major features. Except as
+necessary to avoid confusion, details of library implementation are
+omitted.
+
+-------------------------------------------
+ The fundamental type-conversion mechanism
+-------------------------------------------
+
+XXX This needs to be rewritten.
+
+Every argument of every wrapped function requires some kind of
+extraction code to convert it from Python to C++. Likewise, the
+function return value has to be converted from C++ to Python.
+Appropriate Python exceptions must be raised if the conversion fails.
+Argument and return types are part of the function's type, and much of
+this tedium can be relieved if the wrapping system can extract that
+information through introspection.
+
+Passing a wrapped C++ derived class instance to a C++ function
+accepting a pointer or reference to a base class requires knowledge of
+the inheritance relationship and how to translate the address of a base
+class into that of a derived class.
+
+------------------
+ Exposing Classes
+------------------
+
+C++ classes and structs are exposed with a similarly-terse interface.
+Given::
+
+ struct World
+ {
+ void set(std::string msg) { this->msg = msg; }
+ std::string greet() { return msg; }
+ std::string msg;
+ };
+
+The following code will expose it in our extension module::
+
+ #include <boost/python.hpp>
+ BOOST_PYTHON_MODULE(hello)
+ {
+ class_<World>("World")
+ .def("greet", &World::greet)
+ .def("set", &World::set)
+ ;
+ }
+
+Although this code has a certain pythonic familiarity, people
+sometimes find the syntax bit confusing because it doesn't look like
+most of the C++ code they're used to. All the same, this is just
+standard C++. Because of their flexible syntax and operator
+overloading, C++ and Python are great for defining domain-specific
+(sub)languages
+(DSLs), and that's what we've done in BPL. To break it down::
+
+ class_<World>("World")
+
+constructs an unnamed object of type ``class_<World>`` and passes
+``"World"`` to its constructor. This creates a new-style Python class
+called ``World`` in the extension module, and associates it with the
+C++ type ``World`` in the BPL type conversion registry. We might have
+also written::
+
+ class_<World> w("World");
+
+but that would've been more verbose, since we'd have to name ``w``
+again to invoke its ``def()`` member function::
+
+ w.def("greet", &World::greet)
+
+There's nothing special about the location of the dot for member
+access in the original example: C++ allows any amount of whitespace on
+either side of a token, and placing the dot at the beginning of each
+line allows us to chain as many successive calls to member functions
+as we like with a uniform syntax. The other key fact that allows
+chaining is that ``class_<>`` member functions all return a reference
+to ``*this``.
+
+So the example is equivalent to::
+
+ class_<World> w("World");
+ w.def("greet", &World::greet);
+ w.def("set", &World::set);
+
+It's occasionally useful to be able to break down the components of a
+Boost.Python class wrapper in this way, but the rest of this paper
+will tend to stick to the terse syntax.
+
+For completeness, here's the wrapped class in use:
+
+>>> import hello
+>>> planet = hello.World()
+>>> planet.set('howdy')
+>>> planet.greet()
+'howdy'
+
+Constructors
+============
+
+Since our ``World`` class is just a plain ``struct``, it has an
+implicit no-argument (nullary) constructor. Boost.Python exposes the
+nullary constructor by default, which is why we were able to write:
+
+>>> planet = hello.World()
+
+However, well-designed classes in any language may require constructor
+arguments in order to establish their invariants. Unlike Python,
+where ``__init__`` is just a specially-named method, In C++
+constructors cannot be handled like ordinary member functions. In
+particular, we can't take their address: ``&World::World`` is an
+error. The library provides a different interface for specifying
+constructors. Given::
+
+ struct World
+ {
+ World(std::string msg); // added constructor
+ ...
+
+we can modify our wrapping code as follows::
+
+ class_<World>("World", init<std::string>())
+ ...
+
+of course, a C++ class may have additional constructors, and we can
+expose those as well by passing more instances of ``init<...>`` to
+``def()``::
+
+ class_<World>("World", init<std::string>())
+ .def(init<double, double>())
+ ...
+
+Boost.Python allows wrapped functions, member functions, and
+constructors to be overloaded to mirror C++ overloading.
+
+Data Members and Properties
+===========================
+
+Any publicly-accessible data members in a C++ class can be easily
+exposed as either ``readonly`` or ``readwrite`` attributes::
+
+ class_<World>("World", init<std::string>())
+ .def_readonly("msg", &World::msg)
+ ...
+
+and can be used directly in Python:
+
+>>> planet = hello.World('howdy')
+>>> planet.msg
+'howdy'
+
+This does *not* result in adding attributes to the ``World`` instance
+``__dict__``, which can result in substantial memory savings when
+wrapping large data structures. In fact, no instance ``__dict__``
+will be created at all unless attributes are explicitly added from
+Python. BPL owes this capability to the new Python 2.2 type system,
+in particular the descriptor interface and ``property`` type.
+
+In C++, publicly-accessible data members are considered a sign of poor
+design because they break encapsulation, and style guides usually
+dictate the use of "getter" and "setter" functions instead. In
+Python, however, ``__getattr__``, ``__setattr__``, and since 2.2,
+``property`` mean that attribute access is just one more
+well-encapsulated syntactic tool at the programmer's disposal. BPL
+bridges this idiomatic gap by making Python ``property`` creation
+directly available to users. So if ``msg`` were private, we could
+still expose it as attribute in Python as follows::
+
+ class_<World>("World", init<std::string>())
+ .add_property("msg", &World::greet, &World::set)
+ ...
+
+The example above mirrors the familiar usage of properties in Python
+2.2+:
+
+>>> class World(object):
+... __init__(self, msg):
+... self.__msg = msg
+... def greet(self):
+... return self.__msg
+... def set(self, msg):
+... self.__msg = msg
+... msg = property(greet, set)
+
+Operators and Special Functions
+===============================
+
+The ability to write arithmetic operators for user-defined types that
+C++ and Python both allow the definition of has been a major factor in
+the popularity of both languages for scientific computing. The
+success of packages like NumPy attests to the power of exposing
+operators in extension modules. In this example we'll wrap a class
+representing a position in a large file::
+
+ class FilePos { /*...*/ };
+
+ // Linear offset
+ FilePos operator+(FilePos, int);
+ FilePos operator+(int, FilePos);
+ FilePos operator-(FilePos, int);
+
+ // Distance between two FilePos objects
+ int operator-(FilePos, FilePos);
+
+ // Offset with assignment
+ FilePos& operator+=(FilePos&, int);
+ FilePos& operator-=(FilePos&, int);
+
+ // Comparison
+ bool operator<(FilePos, FilePos);
+
+The wrapping code looks like this::
+
+ class_<FilePos>("FilePos")
+ .def(self + int()) // __add__
+ .def(int() + self) // __radd__
+ .def(self - int()) // __sub__
+
+ .def(self - self) // __sub__
+
+ .def(self += int()) // __iadd__
+ .def(self -= int()) // __isub__
+
+ .def(self < self); // __lt__
+ ;
+
+The magic is performed using a simplified application of "expression
+templates" [VELD1995]_, a technique originally developed by for
+optimization of high-performance matrix algebra expressions. The
+essence is that instead of performing the computation immediately,
+operators are overloaded to construct a type *representing* the
+computation. In matrix algebra, dramatic optimizations are often
+available when the structure of an entire expression can be taken into
+account, rather than processing each operation "greedily".
+Boost.Python uses the same technique to build an appropriate Python
+callable object based on an expression involving ``self``, which is
+then added to the class.
+
+Inheritance
+===========
+
+C++ inheritance relationships can be represented to Boost.Python by adding
+an optional ``bases<...>`` argument to the ``class_<...>`` template
+parameter list as follows::
+
+ class_<Derived, bases<Base1,Base2> >("Derived")
+ ...
+
+This has two effects:
+
+1. When the ``class_<...>`` is created, Python type objects
+ corresponding to ``Base1`` and ``Base2`` are looked up in the BPL
+ registry, and are used as bases for the new Python ``Derived`` type
+ object [#mi]_, so methods exposed for the Python ``Base1`` and
+ ``Base2`` types are automatically members of the ``Derived`` type.
+ Because the registry is global, this works correctly even if
+ ``Derived`` is exposed in a different module from either of its
+ bases.
+
+2. C++ conversions from ``Derived`` to its bases are added to the
+ Boost.Python registry. Thus wrapped C++ methods expecting (a
+ pointer or reference to) an object of either base type can be
+ called with an object wrapping a ``Derived`` instance. Wrapped
+ member functions of class ``T`` are treated as though they have an
+ implicit first argument of ``T&``, so these conversions are
+ necessary to allow the base class methods to be called for derived
+ objects.
+
+Of course it's possible to derive new Python classes from wrapped C++
+class instances. Because Boost.Python uses the new-style class
+system, that works very much as for the Python built-in types. There
+is one significant detail in which it differs: the built-in types
+generally establish their invariants in their ``__new__`` function, so
+that derived classes do not need to call ``__init__`` on the base
+class before invoking its methods :
+
+>>> class L(list):
+... def __init__(self):
+... pass
+...
+>>> L().reverse()
+>>>
+
+Because C++ object construction is a one-step operation, C++ instance
+data cannot be constructed until the arguments are available, in the
+``__init__`` function:
+
+>>> class D(SomeBPLClass):
+... def __init__(self):
+... pass
+...
+>>> D().some_bpl_method()
+Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+TypeError: bad argument type for built-in operation
+
+This happened because Boost.Python couldn't find instance data of type
+``SomeBPLClass`` within the ``D`` instance; ``D``'s ``__init__``
+function masked construction of the base class. It could be corrected
+by either removing ``D``'s ``__init__`` function or having it call
+``SomeBPLClass.__init__(...)`` explicitly.
+
+Virtual Functions
+=================
+
+Deriving new types in Python from extension classes is not very
+interesting unless they can be used polymorphically from C++. In
+other words, Python method implementations should appear to override
+the implementation of C++ virtual functions when called *through base
+class pointers/references from C++*. Since the only way to alter the
+behavior of a virtual function is to override it in a derived class,
+the user must build a special derived class to dispatch a polymorphic
+class' virtual functions::
+
+ //
+ // interface to wrap:
+ //
+ class Base
+ {
+ public:
+ virtual int f(std::string x) { return 42; }
+ virtual ~Base();
+ };
+
+ int calls_f(Base const& b, std::string x) { return b.f(x); }
+
+ //
+ // Wrapping Code
+ //
+
+ // Dispatcher class
+ struct BaseWrap : Base
+ {
+ // Store a pointer to the Python object
+ BaseWrap(PyObject* self_) : self(self_) {}
+ PyObject* self;
+
+ // Default implementation, for when f is not overridden
+ int f_default(std::string x) { return this->Base::f(x); }
+ // Dispatch implementation
+ int f(std::string x) { return call_method<int>(self, "f", x); }
+ };
+
+ ...
+ def("calls_f", calls_f);
+ class_<Base, BaseWrap>("Base")
+ .def("f", &Base::f, &BaseWrap::f_default)
+ ;
+
+Now here's some Python code which demonstrates:
+
+>>> class Derived(Base):
+... def f(self, s):
+... return len(s)
+...
+>>> calls_f(Base(), 'foo')
+42
+>>> calls_f(Derived(), 'forty-two')
+9
+
+Things to notice about the dispatcher class:
+
+* The key element which allows overriding in Python is the
+ ``call_method`` invocation, which uses the same global type
+ conversion registry as the C++ function wrapping does to convert its
+ arguments from C++ to Python and its return type from Python to C++.
+
+* Any constructor signatures you wish to wrap must be replicated with
+ an initial ``PyObject*`` argument
+
+* The dispatcher must store this argument so that it can be used to
+ invoke ``call_method``
+
+* The ``f_default`` member function is needed when the function being
+ exposed is not pure virtual; there's no other way ``Base::f`` can be
+ called on an object of type ``BaseWrap``, since it overrides ``f``.
+
+Admittedly, this formula is tedious to repeat, especially on a project
+with many polymorphic classes; that it is necessary reflects
+limitations in C++'s compile-time reflection capabilities. Several
+efforts are underway to write front-ends for Boost.Python which can
+generate these dispatchers (and other wrapping code) automatically.
+If these are successful it will mark a move away from wrapping
+everything directly in pure C++ for many of our users.
+
+---------------
+ Serialization
+---------------
+
+*Serialization* is the process of converting objects in memory to a
+form that can be stored on disk or sent over a network connection. The
+serialized object (most often a plain string) can be retrieved and
+converted back to the original object. A good serialization system will
+automatically convert entire object hierarchies. Python's standard
+``pickle`` module is such a system. It leverages the language's strong
+runtime introspection facilities for serializing practically arbitrary
+user-defined objects. With a few simple and unintrusive provisions this
+powerful machinery can be extended to also work for wrapped C++ objects.
+Here is an example::
+
+ #include <string>
+
+ struct World
+ {
+ World(std::string a_msg) : msg(a_msg) {}
+ std::string greet() const { return msg; }
+ std::string msg;
+ };
+
+ #include <boost/python.hpp>
+ using namespace boost::python;
+
+ struct World_picklers : pickle_suite
+ {
+ static tuple
+ getinitargs(World const& w) { return make_tuple(w.greet()); }
+ };
+
+ BOOST_PYTHON_MODULE(hello)
+ {
+ class_<World>("World", init<std::string>())
+ .def("greet", &World::greet)
+ .def_pickle(World_picklers())
+ ;
+ }
+
+Now let's create a ``World`` object and put it to rest on disk::
+
+ >>> import hello
+ >>> import pickle
+ >>> a_world = hello.World("howdy")
+ >>> pickle.dump(a_world, open("my_world", "w"))
+
+In a potentially *different script* on a potentially *different
+computer* with a potentially *different operating system*::
+
+ >>> import pickle
+ >>> resurrected_world = pickle.load(open("my_world", "r"))
+ >>> resurrected_world.greet()
+ 'howdy'
+
+Of course the ``cPickle`` module can also be used for faster
+processing.
+
+Boost.Python's ``pickle_suite`` fully supports the ``pickle`` protocol
+defined in the standard Python documentation. There is a one-to-one
+correspondence between the standard pickling methods (``__getinitargs__``,
+``__getstate__``, ``__setstate__``) and the functions defined by the
+user in the class derived from ``pickle_suite`` (``getinitargs``,
+``getstate``, ``setstate``). The ``class_::def_pickle()`` member function
+is used to establish the Python bindings for all user-defined functions
+simultaneously. Correct signatures for these functions are enforced at
+compile time. Non-sensical combinations of the three pickle functions
+are also rejected at compile time. These measures are designed to
+help the user in avoiding obvious errors.
+
+Enabling serialization of more complex C++ objects requires a little
+more work than is shown in the example above. Fortunately the
+``object`` interface (see next section) greatly helps in keeping the
+code manageable.
+
+------------------
+ Object interface
+------------------
+
+Experienced extension module authors will be familiar with the 'C' view
+of Python objects, the ubiquitous ``PyObject*``. Most if not all Python
+'C' API functions involve ``PyObject*`` as arguments or return type. A
+major complication is the raw reference counting interface presented to
+the 'C' programmer. E.g. some API functions return *new references* and
+others return *borrowed references*. It is up to the extension module
+writer to properly increment and decrement reference counts. This
+quickly becomes cumbersome and error prone, especially if there are
+multiple execution paths.
+
+Boost.Python provides a type ``object`` which is essentially a high
+level wrapper around ``PyObject*``. ``object`` automates reference
+counting as much as possible. It also provides the facilities for
+converting arbitrary C++ types to Python objects and vice versa.
+This significantly reduces the learning effort for prospective
+extension module writers.
+
+Creating an ``object`` from any other type is extremely simple::
+
+ object o(3);
+
+``object`` has templated interactions with all other types, with
+automatic to-python conversions. It happens so naturally that it's
+easily overlooked.
+
+The ``extract<T>`` class template can be used to convert Python objects
+to C++ types::
+
+ double x = extract<double>(o);
+
+All registered user-defined conversions are automatically accessible
+through the ``object`` interface. With reference to the ``World`` class
+defined in previous examples::
+
+ object as_python_object(World("howdy"));
+ World back_as_c_plus_plus_object = extract<World>(as_python_object);
+
+If a C++ type cannot be converted to a Python object an appropriate
+exception is thrown at runtime. Similarly, an appropriate exception is
+thrown if a C++ type cannot be extracted from a Python object.
+``extract<T>`` provides facilities for avoiding exceptions if this is
+desired.
+
+The ``object::attr()`` member function is available for accessing
+and manipulating attributes of Python objects. For example::
+
+ object planet(World());
+ planet.attr("set")("howdy");
+
+``planet.attr("set")`` returns a callable ``object``. ``"howdy"`` is
+converted to a Python string object which is then passed as an argument
+to the ``set`` method.
+
+The ``object`` type is accompanied by a set of derived types
+that mirror the Python built-in types such as ``list``, ``dict``,
+``tuple``, etc. as much as possible. This enables convenient
+manipulation of these high-level types from C++::
+
+ dict d;
+ d["some"] = "thing";
+ d["lucky_number"] = 13;
+ list l = d.keys();
+
+This almost looks and works like regular Python code, but it is pure C++.
+
+=================
+ Thinking hybrid
+=================
+
+For many applications runtime performance considerations are very
+important. This is particularly true for most scientific applications.
+Often the performance considerations dictate the use of a compiled
+language for the core algorithms. Traditionally the decision to use a
+particular programming language is an exclusive one. Because of the
+practical and mental difficulties of combining different languages many
+systems are written in just one language. This is quite unfortunate
+because the price payed for runtime performance is typically a
+significant overhead due to static typing. For example, our experience
+shows that developing maintainable C++ code is typically much more
+time-consuming and requires much more hard-earned working experience
+than developing useful Python code. A related observation is that many
+compiled packages are augmented by some type of rudimentary scripting
+layer. These ad hoc solutions clearly show that many times a compiled
+language alone does not get the job done. On the other hand it is also
+clear that a pure Python implementation is too slow for numerically
+intensive production code.
+
+Boost.Python enables us to *think hybrid* when developing new
+applications. Python can be used for rapidly prototyping a
+new application. Python's ease of use and the large pool of standard
+libraries give us a head start on the way to a first working system. If
+necessary, the working procedure can be used to discover the
+rate-limiting algorithms. To maximize performance these can be
+reimplemented in C++, together with the Boost.Python bindings needed to
+tie them back into the existing higher-level procedure.
+
+Of course, this *top-down* approach is less attractive if it is clear
+from the start that many algorithms will eventually have to be
+implemented in a compiled language. Fortunately Boost.Python also
+enables us to pursue a *bottom-up* approach. We have used this approach
+very successfully in the development of a toolbox for scientific
+applications (scitbx) that we will describe elsewhere. The toolbox
+started out mainly as a library of C++ classes with Boost.Python
+bindings, and for a while the growth was mainly concentrated on the C++
+parts. However, as the toolbox is becoming more complete, more and more
+newly added functionality can be implemented in Python. We expect this
+trend to continue, as illustrated qualitatively in this figure:
+
+.. image:: python_cpp_mix.png
+
+This figure shows the ratio of newly added C++ and Python code over
+time as new algorithms are implemented. We expect this ratio to level
+out near 70% Python. The increasing ability to solve new problems
+mostly with the easy-to-use Python language rather than a necessarily
+more arcane statically typed language is the return on the investment
+of learning how to use Boost.Python. The ability to solve some problems
+entirely using only Python will enable a larger group of people to
+participate in the rapid development of new applications.
+
+=============
+ Conclusions
+=============
+
+The examples in this paper illustrate that Boost.Python enables
+seamless interoperability between C++ and Python. Importantly, this is
+achieved without introducing a third syntax: the Python/C++ interface
+definitions are written in pure C++. This avoids any problems with
+parsing the C++ code to be interfaced to Python, yet the interface
+definitions are concise and maintainable. Freed from most of the
+development-time penalties of crossing a language boundary, software
+designers can take full advantage of two rich and complimentary
+language environments. In practice it turns out that some things are
+very difficult to do with pure Python/C (e.g. an efficient array
+library with an intuitive interface in the compiled language) and
+others are very difficult to do with pure C++ (e.g. serialization).
+If one has the luxury of being able to design a software system as a
+hybrid system from the ground up there are many new ways of avoiding
+road blocks in one language or the other.
+
+.. I'm not ready to give up on all of this quite yet
+
+.. Perhaps one day we'll have a language with the simplicity and
+ expressive power of Python and the compile-time muscle of C++. Being
+ able to take advantage of all of these facilities without paying the
+ mental and development-time penalties of crossing a language barrier
+ would bring enormous benefits. Until then, interoperability tools
+ like Boost.Python can help lower the barrier and make the benefits of
+ both languages more accessible to both communities.
+
+===========
+ Footnotes
+===========
+
+.. [#mi] For hard-core new-style class/extension module writers it is
+ worth noting that the normal requirement that all extension classes
+ with data form a layout-compatible single-inheritance chain is
+ lifted for Boost.Python extension classes. Clearly, either
+ ``Base1`` or ``Base2`` has to occupy a different offset in the
+ ``Derived`` class instance. This is possible because the wrapped
+ part of BPL extension class instances is never assumed to have a
+ fixed offset within the wrapper.
+
+===========
+ Citations
+===========
+
+.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report,
+ Vol. 7 No. 5 June 1995, pp. 26-31.
+ http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html
diff --git a/libs/python/doc/PyConDC_2003/default.css b/libs/python/doc/PyConDC_2003/default.css
new file mode 100644
index 000000000..f8109bbd3
--- /dev/null
+++ b/libs/python/doc/PyConDC_2003/default.css
@@ -0,0 +1,188 @@
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:copyright: This stylesheet has been placed in the public domain.
+
+boostinspect:nolicense
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+.first {
+ margin-top: 0 }
+
+.last {
+ margin-bottom: 0 }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+dd {
+ margin-bottom: 0.5em }
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.attention, div.caution, div.danger, div.error, div.hint,
+div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.hint p.admonition-title, div.important p.admonition-title,
+div.note p.admonition-title, div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em }
+
+div.footer, div.header {
+ font-size: smaller }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr {
+ width: 75% }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.line-block {
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option-argument {
+ font-style: italic }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+table {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.citation {
+ border-left: solid thin gray ;
+ padding-left: 0.5ex }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.footnote {
+ border-left: solid thin black ;
+ padding-left: 0.5ex }
+
+td, th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+th.docinfo-name, th.field-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ font-size: 100% }
+
+tt {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
diff --git a/libs/python/doc/PyConDC_2003/python_cpp_mix.jpg b/libs/python/doc/PyConDC_2003/python_cpp_mix.jpg
new file mode 100644
index 000000000..755a9605b
--- /dev/null
+++ b/libs/python/doc/PyConDC_2003/python_cpp_mix.jpg
Binary files differ
diff --git a/libs/python/doc/PyConDC_2003/python_cpp_mix.png b/libs/python/doc/PyConDC_2003/python_cpp_mix.png
new file mode 100644
index 000000000..fd74cbb22
--- /dev/null
+++ b/libs/python/doc/PyConDC_2003/python_cpp_mix.png
Binary files differ