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:
This is not creating a Python type; instead it is merely telling Cython how to deal with a C++ type, by adding additional methods as syntax candy for a custom wrapper.
- In many cases, there's no need to resort to inlining, the defaults will suffice.
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...
