enhancements inlinecpp
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.
Example, using a simple container storing floats at integer indices.
#!python from cython import c cdef extern "C++" from "mylib.h": class MyIterator: cdef void move_next(self): c("++self") cdef void move_prev(self): c("--self") cdef float get(self): return c("*self") cdef float __eq__(self, MyIterator other) # defaults to c("self == other") cdef float __ne__(self, MyIterator other) # defaults to c("self != other") cdef float __le__(self, MyIterator other) # defaults to c("self < other") ... class MyContainer: cdef MyIterator begin(self) # present in C++ cdef MyIterator end(self) # present in C++ cdef float __getitem__(self, int key) # defaults to c("self[value]") cdef void __setitem__(self, int key, float value) # defaults to c("self[key] = value") cdef MyContainer __add__(self, MyContainer other) # defaults to c("self + other") # Perhaps in C++ one has "float& middle()", then we can instead wrap it as cdef float middle(self): return c("self.middle()") cdef void set_middle(self, float value): c("self.middle() = value") # Cython code is allowed too cdef bint is_empty(self): return self.begin() == self.end() # Finally, if a function takes a reference, like inc_arg(int& x), one can # use c() to rewrite to taking a pointer instead, saving Cython semantics. void inc_arg(int* value): 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.
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.
The above is not enough.
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)
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)
The c
command could be used to get rudimentary very-low-level OpenMP support, but that's another story...