Supporting C++ interfaces through inline C++ code

This is just Dag's thoughts, nothing official.

C++ and Cython semantics doesn't match in lots of areas (operator overloading, references, f() = 3...).

As the semantics doesn't match anyway, why try to support 90% of it by wedging C++ into Cython?

This is a very different approach: Do not support C++ semantics, but use inline C++ code and "overlay methods" in order to tell Cython which C++ code should be generated from case to case.

Inline C++ methods

Example, using a simple container storing floats at integer indices.

   1 from cython import c
   2 
   3 cdef extern "C++" from "mylib.h":
   4     class MyIterator:
   5         cdef void move_next(self):
   6             c("++self")
   7         cdef void move_prev(self):
   8             c("--self")
   9         cdef float get(self):
  10             return c("*self")
  11         cdef float __eq__(self, MyIterator other) # defaults to c("self == other")
  12         cdef float __ne__(self, MyIterator other) # defaults to c("self != other")
  13         cdef float __le__(self, MyIterator other) # defaults to c("self < other")
  14         ...
  15 
  16     class MyContainer:
  17         cdef MyIterator begin(self) # present in C++
  18         cdef MyIterator end(self)   # present in C++
  19 
  20         cdef float __getitem__(self, int key)             # defaults to c("self[value]")
  21         cdef void __setitem__(self, int key, float value) # defaults to c("self[key] = value")
  22         cdef MyContainer __add__(self, MyContainer other) # defaults to c("self + other")
  23 
  24         # Perhaps in C++ one has "float& middle()", then we can instead wrap it as
  25         cdef float middle(self):
  26             return c("self.middle()")
  27         cdef void set_middle(self, float value):
  28             c("self.middle() = value")
  29 
  30         # Cython code is allowed too
  31         cdef bint is_empty(self):
  32             return self.begin() == self.end()
  33 
  34     # Finally, if a function takes a reference, like inc_arg(int& x), one can
  35     # use c() to rewrite to taking a pointer instead, saving Cython semantics.
  36     void inc_arg(int* value):
  37         c("inc_arg(*value)")

Note that C++ side, operator[] could for instance return a reference, or an object with overloaded operator=.

Notes:

Implementation

The Cython code iter.move_next() would be transformed into mangled_MyIterator_move_next(iter) (assuming iter is a pointer, otherwise prepend &), which would look like

void mangled_MyIterator_move_next(MyIterator* __pyx_self) {
    ++(*__pyx_self);
}

It seems to me that implementing the c command can be done pretty reliable through string substitution.

Outstanding issues for C++ support

The above is not enough.

Conversion of objects

In the same spirit, rather than declaring operator= or operator Type etc., just tell Cython about the types:

cdef extern "C++":
    class MyClass:
        __convertsto__ = (OtherClass, YetAnotherClass)

Thoughts on plain C and inline C methods

There is no reason to keep this to C++, perhaps somebody would think this is convenient for OO-style C code:

cdef extern:
    struct my_type:
        cdef void operation(self): my_type_operation(self)
    cdef void my_type_operation(my_type* obj) 

Note: OpenMP support

The c command could be used to get rudimentary very-low-level OpenMP support, but that's another story...

enhancements/inlinecpp (last edited 2009-04-27 20:21:29 by DagSverreSeljebotn)