Robert Bradshaw, 13.11.2012 23:29:
> On Tue, Nov 13, 2012 at 2:13 PM, Eric Frederich wrote:
>> If the void* for user data has other uses in C perhaps it does in Python as
>> well.
>> Creating the bindings as the cython/Demo/callback example does consumes the
>> void* and makes it unavailable for use from Python.
>>
>> Instead of making the void* user data point to the Python callable, it could
>> be a tuple of length 2. One for the callable and the other for the user
>> data.
>>
>> In Python you can always pass user data using functools.partial
>
> In C, function pointers are just integers, addresses at which the CPU
> should start reading instructions to execute from. It's also hard(er)
> to create new C functions at runtime. Python functions are much
> richer, e.g. you can attach data to them and they can enclose state,
> so you don't need this. (As you note, once you have a user-supplied
> void* you can pass as much data as you want.)
Exactly, you can pass a Python object reference to a nested function, for
example, which inherits its closure (and thus state) from the environment
it was defined in. You could even pass a running Python generator or
coroutine and instead of calling a function in the C callback you'd send
some data into the coroutine or call next() on it. All you really need for
this is a way to pass a single void* through C space, and that's the
problem here.
A less comfortable but still common way to handle this is the use of thread
local storage, in case the callback occurs during a call into the C library
and not at an arbitrary point, e.g. timer triggered. It's a bit more
overhead, but at least it fills the gap of a missing user data pointer in
the C API.
Stefan