Skip to content

Instantly share code, notes, and snippets.

@Vindaar
Created March 11, 2019 09:45
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Vindaar/df44fe0014530b6d61bed91c84a42733 to your computer and use it in GitHub Desktop.
Save Vindaar/df44fe0014530b6d61bed91c84a42733 to your computer and use it in GitHub Desktop.
How to call Nim code from R using `.C` interface

Calling Nim from R

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/

Writing our Nim procedure

Let’s define a simple procedure, which we want Nim to do:

proc add5(x: int): int =
  result = x + 5

How 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 + 5

In 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 + 5

Let’s save this as Rtest.nim and we can compile it using:

nim c -d:release --noMain --app:lib Rtest.nim

After this we should have a libRtest.so in the current directory.

Check if add5 shows up in C code

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.

Call the lib from R

From here on all we need to do is call the code from R. Let’s start R:

R

and 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!

how to call using .Call interface

Still todo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment