Actually, Pymod was designed to be almost an anti-Cython. :)
My issue with Cython is that it's a limited sub-language within Python, where you add Cython elements incrementally & iteratively (diverging from Python in the process) until the code runs "fast enough". I'd rather work directly in a full-featured, internally-self-consistent language from the start. Nim has a clean Pythonic syntax, with all the best parts of C++ (including its runtime speed).
Hence, Pymod takes the form of an `exportpy` annotation (a user-defined Nim pragma) onto existing Nim functions, which are then auto-compiled into a Python extension module.
So there's no gradual divergence of my Python code (as it becomes more "Cythonized"); rather, the high-performance code is written directly in pure Nim. :)
Yes. I use Cython mainly to wrap C++ and it is fairly pleasant. Yes there are still some boilerplates but the wrapping code is clean and easy to read. One can also cut down on the boilerplate by sticking to std library as much as possible at the api level.
After browsing that page, I observe that even when Cython is wrapping an external C library, there's still a notable difference between the way Cython does things & the way Pymod does things.
The explanation on that Cython page begins: "To get started, the first step is to redefine the C API in a .pxd file, say, cqueue.pxd". So to wrap an external C library using Cython, you still need to define an entirely new header-like definition file in Cython's intermediate language.
In contrast, Pymod only requires an `exportpy` pragma annotation at the end of an existing Nim procedure function header -- you don't need to create any intermediate definition files. And the `exportpy` pragma is inert unless you invoke the "pmgen.py" script (a Python script in Pymod that determines the Python C-API system configuration & automates all the compilation), so your Nim code is still completely valid Nim code after you apply the `exportpy` annotation.
I'm now largely out of my depth, but much of that will just come down to what is available from Nim and what is available from C? And perhaps some of it from the complexity of supporting arbitrary C code in a flexible way?
Oh absolutely, Nim should definitely get the vast majority of the credit.
It's not just because Nim compiles to C; it's also due to Nim's powerful macro system, which: (1) allows me to define my own first-class pragmas such as `exportpy`; (2) supplies my pragma with a detailed & expressive AST of the Nim function onto which my pragma was annotated; (3) enables my pragma to auto-generate the C-API boilerplate code, and write it to disk as a newly-created C source file, all within the Nim compilation pass. Nim is a fantastic language, perfectly suited to this scenario.
Was any of your design inspired by them? I also wonder how practical it would be to reuse parts of it when making a bridge for another language.