A super short introduction how to call Nim code from R using the .C
interface.
I’m not an R user normally, so I googled and used this post as a
reference:
https://www.r-bloggers.com/three-ways-to-call-cc-from-r/
Let’s define a simple procedure, which we want Nim to do:
proc add5(x: int): int =
result = x + 5How do we get this into a form to call it from R?
The .C interface expects loaded functions to receive arguments via
pointers and does not accept return values. So in C we need something
like:
void add5(int* x){
*x = *x + 5;
}Fortunately in Nim we don’t have to deal with pointers manually. All
we need is to declare the argument as var:
proc add5(x: var int) =
x = x + 5In addition leaving out the return type means we get a void return
type in C.
However, this function will be mangled when compiled to C, so we need
to tell the Nim compiler to leave it as is using the exportc pragma
like so:
proc add5(x: var int) {.exportc: "add5".} =
x = x + 5Let’s save this as Rtest.nim and we can compile it using:
nim c -d:release --noMain --app:lib Rtest.nimAfter this we should have a libRtest.so in the current directory.
Just for curiosity, let’s check whether disabling the name mangling actually worked. Nowadays Nim stores the temporary files in ~/.cache/nim/<project_name>_<build_type> so in our case: ~/.cache/nim/Rtest_r/
If we open the ~/.cache/nim/Rtest_r/Rtest.c and search for add5 we
should find a line like:
N_NIMCALL(void, add5)(NI* x);and further below:
N_NIMCALL(void, add5)(NI* x) {
(*x) = (NI)((*x) + ((NI) 5));
}which is just what we want, a void return type and an NI (Nim
integer) pointer.
From here on all we need to do is call the code from R. Let’s start R:
Rand load the library:
dyn.load("libRtest.so")Now we can use the .C interface to call the add5 function:
.C("add5", x = as.integer(2))should output 7.
That’s all there is to it!
Still todo.