Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: Changeset: r54598:e1487d12d116 Date: 2012-04-20 14:54 -0700 http://bitbucket.org/pypy/pypy/changeset/e1487d12d116/
Log: cppyy documentation: feature list and short intro to PyCintex diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -1,5 +1,5 @@ ============================ -cppyy: C++ bindings for pypy +cppyy: C++ bindings for PyPy ============================ The cppyy module provides C++ bindings for PyPy by using the reflection @@ -26,6 +26,8 @@ For now, the easiest way of getting the latest version of Reflex, is by installing the ROOT package. +Besides getting the latest version of Reflex, another advantage is that with +the full ROOT package, you can also use your Reflex-bound code on `CPython`_. `Download`_ a binary or install from `source`_. Some Linux and Mac systems may have ROOT provided in the list of scientific software of their packager. @@ -54,7 +56,7 @@ This will build a ``pypy-c`` that includes the cppyy module, and through that, Reflex support. -Of course, if you already have a prebuilt version of the ``pypy`` interpreter, +Of course, if you already have a pre-built version of the ``pypy`` interpreter, you can use that for the translation rather than ``python``. .. _`PyPy sources`: https://bitbucket.org/pypy/pypy/overview @@ -72,10 +74,10 @@ $ cat MyClass.h class MyClass { public: - MyClass( int i = -99) : m_myint( i ) {} + MyClass(int i = -99) : m_myint(i) {} int GetMyInt() { return m_myint; } - void SetMyInt( int i ) { m_myint = i; } + void SetMyInt(int i) { m_myint = i; } public: int m_myint; @@ -107,3 +109,185 @@ >>>> help(cppyy.gbl.MyClass) # shows that normal python introspection works That's all there is to it! + + +Features +======== + +The following is not meant to be an exhaustive list, since cppyy is still +under active development. +Furthermore, the intention is that every feature is as natural as possible on +the python side, so if you find something missing in the list below, simply +try it out. +It is not always possible to provide exact mapping between python and C++ +(active memory management is one such case), but by and large, if the use of a +feature does not strike you as obvious, it is more likely to simply be a bug. +That is a strong statement to make, but also a worthy goal. + +* **abstract classes**: Are represented as python classes, since they are + needed to complete the inheritance hierarchies, but will raise an exception + if an attempt is made to instantiate from them. + +* **arrays**: Supported for builtin data types only, as used from module + ``array``. + Out-of-bounds checking is limited to those cases where the size is known at + compile time (and hence part of the reflection info). + +* **builtin data types**: Map onto the expected equivalent python types, with + the caveat that there may be size differences, and thus it is possible that + exceptions are raised if an overflow is detected. + +* **casting**: Is supposed to be unnecessary. + Object pointer returns from functions provide the most derived class known + in the hierarchy of the object being returned. + This is important to preserve object identity as well as to make casting, + a pure C++ feature after all, superfluous. + +* **classes and structs**: Get mapped onto python classes, where they can be + instantiated as expected. + If classes are inner classes or live in a namespace, their naming and + location will reflect that. + +* **data members**: Public data members are represented as python properties + and provide read and write access on instances as expected. + +* **default arguments**: C++ default arguments work as expected, but python + keywords are not supported. + It is technically possible to support keywords, but for the C++ interface, + the formal argument names have no meaning and are not considered part of the + API, hence it is not a good idea to use keywords. + +* **doc strings**: The doc string of a method or function contains the C++ + arguments and return types of all overloads of that name, as applicable. + +* **functions**: Work as expected and live in their appropriate namespace + (which can be the global one, ``cppyy.gbl``). + +* **inheritance**: All combinations of inheritance on the C++ (single, + multiple, virtual) are supported in the binding. + However, new python classes can only use single inheritance from a bound C++ + class. + Multiple inheritance would introduce two "this" pointers in the binding. + This is a current, not a fundamental, limitation. + The C++ side will not see any overridden methods on the python side, as + cross-inheritance is planned but not yet supported. + +* **methods**: Are represented as python methods and work as expected. + They are first class objects and can be bound to an instance. + Virtual C++ methods work as expected. + To select a specific virtual method, do like with normal python classes + that override methods: select it from the class that you need, rather than + calling the method on the instance. + +* **namespaces**: Are represented as python classes. + Namespaces are open-ended than classes, so sometimes initial access may + result in updates as data and functions are looked up and constructed + lazily. + Thus the result of ``dir()`` on a namespace should not be relied upon: it + only shows the already accessed members. (TODO: to be fixed by implementing + __dir__.) + The global namespace is ``cppyy.gbl``. + +* **operator conversions**: If defined in the C++ class and a python + equivalent exists (i.e. all builtin integer and floating point types, as well + as ``bool``), it will map onto that python conversion. + Note that ``char*`` is mapped onto ``__str__``. + +* **operator overloads**: If defined in the C++ class and if a python + equivalent is available (not always the case, think e.g. of ``operator||``), + then they work as expected. + Special care needs to be taken for global operator overloads in C++: first, + make sure that they are actually reflected, especially for the global + overloads for ``operator==`` and ``operator!=`` of STL iterators in the case + of gcc. + Second, make sure that reflection info is loaded in the proper order. + I.e. that these global overloads are available before use. + +* **pointers**: For builtin data types, see arrays. + For objects, a pointer to an object and an object looks the same, unless + the pointer is a data member. + In that case, assigning to the data member will cause a copy of the pointer + and care should be taken about the object's live time. + If a pointer is a global variable, the C++ side can replace the underlying + object and the python side will immediately reflect that. + +* **static data members**: Are represented as python property objects on the + class and the meta-class. + Both reading and write access is as expected. + +* **static methods**: Are represented as python's ``staticmethod`` objects + and can be called both from the class as well as from instances. + +* **strings**: The std::string class is considered a builtin C++ type and + mixes quite well with python's str. + Python's str can be passed where a ``const char*`` is expected, and an str + will be returned if the return type is ``const char*``. + +* **templated classes**: Are represented in a meta-class style in python. + This looks a little bit confusing, but conceptually is rather natural. + For example, given the class ``std::vector<int>``, the meta-class part would + be ``std.vector`` in python. + Then, to get the instantiation on ``int``, do ``std.vector(int)`` and to + create an instance of that class, do ``std.vector(int)()``. + Note that templates can be build up by handing actual classes to the class + instantiation, or by passing in the list of template arguments as a string. + The former is a lot easier to work with if you have template instantiations + using classes that themselves are templates (etc.) in the arguments. + All classes must already exist in the loaded reflection info. + +* **unary operators**: Are supported if a python equivalent exists, and if the + operator is defined in the C++ class. + +You can always find more detailed examples and see the full of supported +features by looking at the tests in pypy/module/cppyy/test. + +CPython +======= + +Most of the ideas in cppyy come originally from the `PyROOT`_ project. +Although PyROOT does not support Reflex directly, it has an alter ego called +"PyCintex" that, in a somewhat roundabout way, does. +If you installed ROOT, rather than just Reflex, PyCintex should be available +immediately if you add ``$ROOTSYS/lib`` to the ``PYTHONPATH`` environment +variable. + +.. _`PyROOT`: http://root.cern.ch/drupal/content/pyroot + +There are a couple of minor differences between PyCintex and cppyy, most to do +with naming. +The one that you will run into directly, is that PyCintex uses a function +called ``loadDictionary`` rather than ``load_reflection_info``. +The reason for this is that Reflex calls the shared libraries that contain +reflection info "dictionaries." +However, in python, the name `dictionary` already has a well-defined meaning, +so a more descriptive name was chosen for cppyy. +In addition, PyCintex requires that the names of shared libraries so loaded +start with "lib" in their name. +The basic example above, rewritten for PyCintex thus goes like this:: + + $ python + >>>> import PyCintex + >>>> PyCintex.loadDictionary("libMyClassDict.so") + >>>> myinst = PyCintex.gbl.MyClass(42) + >>>> print myinst.GetMyInt() + 42 + >>>> myinst.SetMyInt(33) + >>>> print myinst.m_myint + 33 + >>>> myinst.m_myint = 77 + >>>> print myinst.GetMyInt() + 77 + >>>> help(PyCintex.gbl.MyClass) # shows that normal python introspection works + +Other naming differences are such things as taking an address of an object. +In PyCintex, this is done with ``AddressOf`` whereas in cppyy the choice was +made to follow the naming as in ``ctypes`` and hence use ``addressof`` +(PyROOT/PyCintex predate ``ctypes`` by several years, and the ROOT project +follows camel-case, hence the differences). + +Of course, this is python, so if any of the naming is not to your liking, all +you have to do is provide a wrapper script that you import instead of +importing the ``cppyy`` or ``PyCintex`` modules directly. +In that wrapper script you can rename methods exactly the way you need it. + +In the Cling world, all these differences will be resolved. diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -28,7 +28,6 @@ .. _ctypes: #CTypes .. _\_ffi: #LibFFI .. _mixedmodule: #Mixed Modules -.. _Reflex: #Reflex CTypes ====== _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit