I am developing a package for R and would like to load the functionalities of an R package inside an Rcpp function.
I know about Rcpp::Environment env("package:package_of_interest"), but this only works when the "package_of_interest" is loaded from R via library("package_of_interest"). Furthermore, I added the "package_of_interest" in the DESCRIPTION file below DEPENDS. That means, whenever I load my package with library("my_package") in R all functionalities are given as the desired package is auto-loaded. However, if I call the function via my_package::my_functionX(...) it drops an error and states that it can't convert the object to an environment: [type=character; target=ENVSXP]. Is there any way to solve this problem? Can I convert the input (character) to target (ENVSXP)?
I previously studied Call a function from c via environment Rcpp and Rcpp trouble importing 'hessian' from R package 'numDeriv' and was confirmed with my approach.
In the following, I give you a minimal example to reproduce the error. With library(bigmemory) called first, this will work, but without not.
#include <iostream>
// [[Rcpp::depends(RcppArmadillo, BH, bigmemory)]]
#include <bigmemory/BigMatrix.h>
#include <bigmemory/MatrixAccessor.hpp>
#include <RcppArmadillo.h>
#include <Rdefines.h>
// [[Rcpp::export]]
void test_make_bm(std::size_t nrows, std::size_t ncols, std::string type,
bool separated = false, bool binarydescriptor = false, bool shared = true)
{
// this line drops the error
Rcpp::Environment bigmemory = Rcpp::Environment("package:bigmemory");
// you can also directly call Rcpp::Environment bigmemory("package:bigmemory")
Rcpp::Function big_matrix = bigmemory["big.matrix"];
SEXP bm = big_matrix(
Rcpp::_["nrow"] = nrows,
Rcpp::_["ncol"] = ncols,
Rcpp::_["type"] = type,
Rcpp::_["init"] = R_NilValue,
Rcpp::_["dimnames"] = R_NilValue,
Rcpp::_["separated"] = separated,
Rcpp::_["backingfile"] = R_NilValue,
Rcpp::_["backingpath"] = R_NilValue,
Rcpp::_["descriptorfile"] = R_NilValue,
Rcpp::_["binarydescriptor"] = binarydescriptor,
Rcpp::_["shared"] = shared);
SEXP address = GET_SLOT(bm, Rf_install("address"));
Rcpp::XPtr<BigMatrix> xptr(address);
arma::mat m((double*) xptr->matrix(), xptr->nrow(), xptr->ncol());
m.print();
Rcpp::Rcout << "\n";
return;
}
Is there any way to load the package from Rcpp? Does anyone know why bigmemory's BigMatrix has no constructor in C ?
CodePudding user response:
This is essentially the same as one of the unit test files, this has been documented behavior for as long as it existed. If you need a function from a package that is not yet attached, you need to go via the namespace.
> Rcpp::cppFunction(paste0("double mysd(NumericVector x) { ",
r"(Environment ns = Environment::namespace_env("stats");)",
r"(Function f = ns["sd"]; return as<double>(f(x)); })"))
> mysd(1:10)
[1] 3.02765
> mysd(1:10)
[1] 3.02765
>
(I split the cppFunction()
call over three lines for readability, but you can make it just one which is also how I wrote it to test this.)
CodePudding user response:
So after some research, I present you the solution. In order to get access to the packagename::package_function() functionality you have to use the namespace_env function from the Environment namespace.
#include <iostream>
// [[Rcpp::depends(RcppArmadillo, BH, bigmemory)]]
#include <bigmemory/BigMatrix.h>
#include <bigmemory/MatrixAccessor.hpp>
#include <RcppArmadillo.h>
#include <Rdefines.h>
// [[Rcpp::export]]
void test_make_bm(std::size_t nrows, std::size_t ncols, std::string type,
bool separated = false, bool binarydescriptor = false, bool shared = true)
{
Rcpp::Environment bigmemory = Rcpp::Environment::namespace_env("bigmemory");
Rcpp::Function big_matrix = bigmemory["big.matrix"];
SEXP bm = big_matrix(
Rcpp::_["nrow"] = nrows,
Rcpp::_["ncol"] = ncols,
Rcpp::_["type"] = type,
Rcpp::_["init"] = R_NilValue,
Rcpp::_["dimnames"] = R_NilValue,
Rcpp::_["separated"] = separated,
Rcpp::_["backingfile"] = R_NilValue,
Rcpp::_["backingpath"] = R_NilValue,
Rcpp::_["descriptorfile"] = R_NilValue,
Rcpp::_["binarydescriptor"] = binarydescriptor,
Rcpp::_["shared"] = shared);
SEXP address = GET_SLOT(bm, Rf_install("address"));
Rcpp::XPtr<BigMatrix> xptr(address);
arma::mat m((double*) xptr->matrix(), xptr->nrow(), xptr->ncol());
m.print();
Rcpp::Rcout << "\n";
return;
}