klmr / box

Write reusable, composable and modular R code

Home Page:https://klmr.me/box/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add support for `Rcpp::sourceCpp` inside a `box` module

dereckmezquita opened this issue · comments

Please describe your feature request

I just want to be able to use a Rcpp::sourceCpp inside a module. The problem is that there is no explicit way to import an Rcpp function to a variable name, it just goes to the global scope.

When I try to import my box module that is using a Rcpp::sourceCpp function I get a not found error. Then when I do browser() to check the environment inside that module and I print the name of my function that should have been sourced indeed it is not available.

some_simple_fun.cpp

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double meanC(NumericVector x) {
  int n = x.size();
  double total = 0;

  for(int i = 0; i < n; ++i) {
    total += x[i];
  }
  return total / n;
}

some_box_module.R

Rcpp::sourceCpp("./some_simple_fun.cpp")

#' @export
some_fun <- function(x) {
    # meanC is not found
    meanC(x)
}

main.R

box::use(./some_box_module)
Error in box::use(./some_box_module) : 
  object 'meanC' not found
(inside “eval(exprs, mod_ns)”)
(inside “box::use(./some_box_module)”)

By default, sourceCpp() will add the objects to the global environment. If you wish to add them to some other environment, you must specify which. I think:

Rcpp::sourceCpp("./some_simple_fun.cpp", env = environment())

would solve your issue. It should add meanC to your current environment, the module's namespace.

One other small suggestion. I would use Rcpp::sourceCpp(box::file("some_simple_fun.cpp"), env = environment()) so that it is independent of working directory.

Hope this helps!

This is great thank you; this accomplishes what I need!

@ArcadeAntics Excellent reply, that’s exactly right.

One small addition: using environment() works (only) when Rcpp::sourceCpp is called at module level (i.e. file scope). If it is called inside a function this won’t work because environment() refers to the function’s (transient) execution environment.

‘box’ currently does not yet support finding the module environment in a straightforward manner (except inside .on_load and .on_unload, via the ns parameter). Adding a function that returns the module environment is planned (see #310). However, you can’t execute Rcpp::sourceCpp inside arbitrary functions anyway, since the module namespace is sealed after loading. The only exception is .on_load, which is explicitly permitted to modify the module namespace.

Please also note that, to future-proof your code, you should ideally not call Rcpp::sourceCpp and similar functions at file scope, but rather inside .on_load. That’s because it’s planned that future versions of ‘box’ will cache the module code and won’t re-execute code at file scope (similar to how R packages work). Instead, the .on_load hook is executed.