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...