CEP 526 - Cython ABI for cdef functions
This CEP proposes some changes to the Cython language to make things easier for new users.
Making except function annotations optional
We change the internal Cython ABI so that exception propagation information is always passed. If an except annotation is used, propagation happens the same way as today. However, if except is not specified, then an extra int* out-argument is appended at the end of the argument list which is set to -1 on error and set to 0 on success.
To maintain compatability with C, whenever you take the address of the function you actually get the address of a wrapper which traps the exception and calls __Pyx_WriteUnraisable(). Functions with an except clause works as today, without a wrapper.
In the module function table, one pointer is exported both for the Cython ABI and for the C ABI, so that other Cython modules can also call the function through the Cython ABI or get its C ABI pointer.
with gil function annotation
Also by making use of a wrapper, we deprecate the with gil function annotation. The cases where one would use this today is instead moved to the calling code, where there is more context available. Today one would do:
cdef void foo() with gil: print "in foo" with nogil: foo() # this is OK today
This CEP proposes that one deprecates with gil on the function, and instead use a with gil block:
with nogil: ... with gil: foo()
When passing a callback to C code, one would get the address of a GIL-acquiring wrapper:
cdef void foo(): print "in foo" with nogil: call_c_code(&foo) (&foo)() # also OK in fact without holding GIL
Interaction between GIL-acquiring wrapper and exception-catching wrapper
The wrappers proposed in the above two sections are one and the same. That is:
cdef void func1(): ... # &func1 is a wrapper which both ensures that one has the GIL # and catches exceptions cdef void func2() nogil: ... # &func1 is a wrapper which catches exceptions only cdef int func3() except -1: ... # &func3 is a wrapper which only ensures the GIL cdef int func4() except -1 nogil: # There is no wrapper, Cython ABI and C ABI are the same and # &func4 gets the "real" function address
Skipping the wrapper
It is possible to skip the except-catching and/or GIL-acquiring wrapper by calling a new builtin cython.address_cython_abi. The type of the returned pointer will then include the success out-argument, unless there is an "except" clause.
cdef class methods
There should be no need for a wrapper for cdef class methods (in a sense they already has a Cython-specific ABI).
Binary compatability between Cython versions
Cython modules get an attribute with the ABI revision, so that we can fail if one tries to early-bind with a Cython module compiled with another Cython version.