The FFI support variadic C functions with the #:varargs-after
option. I have run into the error: PyObject_CallMethodObjArgs: arity mismatch;
the expected number of arguments does not match the given number
expected: 3
given: 4
where PyObject_CallMethodObjArgs
is defined like this: ; PyObject *PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)
(define-python PyObject_CallMethodObjArgs (_fun #:varargs-after 2
_PyObject* _PyObject* _pointer -> _PyObject*))
The call site looks like this: (define result (apply PyObject_CallMethodObjArgs
pyobj
(string->py-string method-str)
pyargs))
I am surprised that the error says that 3 arguments are expected, when the function is variadic.
What am I missing?
#:varargs-after
does not mean that you can supply any number of arguments to the FFI-generated Racket function. You need a separate FFI-generated function for each number of arguments that you want to supply. The #:varargs-after
annotation indicates how many of the arguments are before …
in the C prototype.
Got it! That’s reasonable easy to fix.
Is this a limitation of ffilib
?
Yes, but also Chez Scheme, and really a kind of fundamental limitation. You may have in mind that _pointer
would be replicated N times for N extra arguments, but more generally, the extra arguments represented by …
in a C prototype can have different types among arguments (and differnet types for different calls). In C, a call site effectively has an inferred type for the function; in Racket, you have to be explicit by creating a new type for each combination of arguments.
In this case all the extra arguments have the same type (a pointer) and the last argument is NULL.
I’ll just make functions for 0 to 5 arguments and call it a day.
@soegaard2 Out of curiosity, in what context are you writing bindings for Python? It’s not on my agenda at the moment, but it’s something I’ve thought about doing.
@philip.mcgrath I have finally realised that to bring “Scientific Computing” to Racket, we need bindings for Numpy (and related projects). Turns out Python has a libpython
that can be used to embed it. The Python C-API is reasonably easy to use and seems a good fit to be used from Racket.
Right now I can start Python, convert values back and forth and call Python functions. I am experimenting with a pyffi
that works analogous to the C FFI. I used it to write bindings for almost all of the functions in the builtins
module Now I have begon working on ndarray
from Numpy.
My plan is to present the work, when the core parts are stable. And hopefully get some help to write bindings for some of the most useful Python libraries.
That is basically why I have been interested: it’s not even the Python code so much as the thin layers over C or Cython, from what I’ve seen. (These also make Python much less memory-safe than it gets credit for. I still have not forgiven the dependency that wanted a faster JSON library, used one in C, and segfaulted.)
I recently learned of another effort at bindings for libpython in Racket, also: https://github.com/Aeva/snake-oil\|https://github.com/Aeva/snake-oil
One thing I’ve never been decided about is how/whether Racket’s modules and namespaces should correspond to Python environments.
If numpy is a thin C wrapper, would it be easier to try an FFI wrapper over that directly instead of going through Python? Or are they too entangled?
@philip.mcgrath Thanks for the pointer. I had missed Aeva’s library.
@ben.knoble There is a C API for Numpy, but they expose everything as Python objects. https://numpy.org/doc/stable/reference/c-api/index.html
@ben.knoble I hope the Numpy C-PI can be used to take an array of numbers (like a flvector
or a fxvector
and turn it into a ndarray
without copying the data.
The fact that PyPy implements the CPython API always amazes me.
hi can you guys recommend racket libraries for computer music? i would like to make classical music with racket