It's easy to create active bindings in R via makeActiveBinding().
This package faciliates the creation of active bindings that link back to C++ code.
It provides an interface that allows binding several identifiers in an environment to the same C++ function,
which is then called with the name (and a payload) as argument.
It is recommended to use the newer _wrapped functions that support passing an arbitrary Rcpp::List as payload.
This allows to store an Rcpp::XPtr to a C++ object in that list.
The XPtr then will be released when the payload is garbage-collected, and the C++ object will be destroyed.
You can install bindrcpp from github with:
# install.packages("pak")
# pak::pak("krlmlr/bindrcpp")
install.packages("bindrcpp", repos = c('https://krlmlr.r-universe.dev', 'https://cloud.r-project.org'))
The following C++ module exports a function test_tolower_bindings()
that creates active bindings that return the binding name in lowercase.
#include <Rcpp.h>
// [[Rcpp::depends(bindrcpp)]]
#include <bindrcpp.h>
#include <algorithm>
#include <string>
using namespace Rcpp;
using namespace bindrcpp;
SEXP tolower_callback(const String& name, PAYLOAD) {
std::string name_string = name;
std::transform(name_string.begin(), name_string.end(), name_string.begin(), ::tolower);
return CharacterVector(name_string);
}
// [[Rcpp::export]]
SEXP test_tolower_bindings(CharacterVector names, Environment parent) {
// We don't pass any payload here
return bindrcpp::create_env_string(
names, &tolower_callback, PAYLOAD(NULL), parent);
}
This function can be called from R:
env <- test_tolower_bindings(c("Converting", "to", "LOWERCASE"), .GlobalEnv)
ls(env)
#> [1] "Converting" "LOWERCASE" "to"
env$Converting
#> [1] "converting"
env$to
#> [1] "to"
env$LOWERCASE
#> [1] "lowercase"
env$y
#> NULL
The bindings are read-only:
env$Converting <- "CONVERTING"
#> Error:
#> ! Binding is read-only.