--- title: "Calling R from C" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Calling R from C} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) knitr::knit_engines$set(callme = callme:::callme_engine) library(callme) ``` ```{css, echo=FALSE} .callme { background-color: #E3F2FD; } pre.callme span { background-color: #E3F2FD; } ``` ## Introduction Calling an R function from C involves: * Creating a special list of function name and arguments * Optionally setting the argument names with `SET_TAG()` * Calling `eval()` Creating the special list for the call can be done using the helper methods `lang1()` to `lang6()`, or for R 4.4.1 or later `allocLang()` can provide more flexibility if needed. ## `lang1()` - Calling an R function with no arguments `lang1()` is for assembling a call to an R function without specifying any arguments. In this example `getwd()` is called from C using `lang1()` ```{callme} SEXP call_r_from_c_with_lang1(void) { SEXP my_call = PROTECT(lang1( PROTECT(Rf_install("getwd")) )); SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); UNPROTECT(3); return my_result; } ``` ```{r} call_r_from_c_with_lang1() ``` ## `lang2()` - Calling an R function with a single unnamed argument `lang2()` is for assembling a call to an R function and specifying a single argument. In this example `abs(-1)` is called from C using `lang2()` ```{callme} SEXP call_r_from_c_with_lang2(void) { SEXP val = PROTECT(ScalarReal(-1)); SEXP my_call = PROTECT(lang2( PROTECT(Rf_install("abs")), val )); SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); UNPROTECT(4); return my_result; } ``` ```{r} call_r_from_c_with_lang2() ``` ## `lang2()` - Calling an R function with a single named argument In this example `tempfile(fileext = ".txt")` is called from C using `lang2()` ```{callme} SEXP call_r_from_c_with_lang2_named(void) { // Assemble the function + argument with name SEXP val = PROTECT(mkString(".txt")); SEXP my_call = PROTECT(lang2( PROTECT(Rf_install("tempfile")), val )); // Set the argument name SEXP t = CDR(my_call); SET_TAG(t, Rf_install("fileext")); // Evaluate the call SEXP my_result = PROTECT(eval(my_call, R_GlobalEnv)); UNPROTECT(4); return my_result; } ``` ```{r} call_r_from_c_with_lang2_named() ``` ## Using `allocLang()` (R >= 4.4.1 only) The C code is equivalent to this R code: ```{r eval = FALSE} print(pi , digits = 3) ``` ```{callme eval=(getRversion() >= "4.4.1")} #| invisible=TRUE, compile=FALSE SEXP call_print_from_c(SEXP value, SEXP digits) { // Allocate a new call object SEXP my_call = PROTECT(allocLang(3)); // Manipulate a pointer to this call object to // fill in the arguments and set argument names SEXP t = my_call; SETCAR(t, install("print")); t = CDR(t); SETCAR(t, value) ; t = CDR(t); SETCAR(t, digits); SET_TAG(t, install("digits")); eval(my_call, R_GlobalEnv); UNPROTECT(1); return R_NilValue; } ``` ```{r eval=FALSE} call_print_from_c(pi, digits = 3) ```