R Package Integration with Modern Reusable C++ Code Using Rcpp – Part 2
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Daniel Hanson is a full-time lecturer in the Computational Finance & Risk Management program within the Department of Applied Mathematics at the University of Washington. His appointment followed over 25 years of experience in private sector quantitative development in finance and data science.
In the first post in this series, we looked at configuring a Windows 10 environment for using the Rcpp
package. However, what follows below, and going forward, is applicable to an up-to-date R, RStudio, and Rcpp
configuration on any operating system.
Today, we will examine design considerations in integrating standard and portable C++ code in an R package, using Rcpp
in the interface level alone. This will ensure no R-related dependencies are introduced into the C++ code base. In general, of course, best programming practices say we should strive to keep interface and implementation separate.
Design Considerations
For this discussion, we will assume the package developer has access to a repository of standard C++ code that is intended for use with other mathematical or scientific applications and interfaces. The goal is integrate this code into an R package, and then export functions to R that will use this existing C++ code. The end users need not be concerned that they are using C++ code; they will only see the exported functions that can be used and called like any other R function.
The package developer, at this stage, has two components that cannot communicate with each other, at least yet:
Establishing Communication
This is where Rcpp
comes in. We will create an interface layer that utilizes functions and objects in the Rcpp
C++ namespace that facilitate communication between R and C++. This interface will ensure that no dependence on R or Rcpp
is introduced into our reusable code base.
The Rcpp
namespace contains a treasure trove of functions and objects that abstract away the terse underlying C interface provided by R, making our job far less painful. However, at this initial stage, to keep the discussion focused on a basic interface example, we will limit our use of Rcpp functions to facilitate the transfer of numeric
vector data in R to the workhorse STL container std::vector<double>
, which is of course ubiquitous in quantitative C++ code.
Conversion between R Vectors and C++ Vectors
The Rcpp::NumericVector
class, as its name suggests, stores data taken from an R numeric vector, but what makes Rcpp even more powerful here is its inclusion of the C++ template function Rcpp::as<T>(.)
. This function safely and efficiently copies the contents of an Rcpp::NumericVector
to a std::vector<double>
object, as demonstrated in Figure 3, below.
Remark: Rcpp also has the function Rcpp::wrap(.)
, which copies values in an STL vector back into an Rcpp::NumericVector
object, so that the results can then be to R; this function will be covered in our next article in this series.
A C++ Interface Function
Figure 3 shows a mythical Rcpp
interface function at the top, called fcn(.)
, and a function in our reusable standard C++ code base called doSomething(.)
. Note first the tag that appears just above the interface function signature. It must be exactly one line above, and there must be a single space only between the second forward slash and the first left square bracket.
This interface function will be exported to R, where it can be called by the same function name, fcn(.)
, taking in an R numeric
vector input. The Rcpp::NumericVector
object takes this data in as the input to C++. The contents are then transferred to a C++ std::vector<double>
, using the Rcpp template function Rcpp::as<vector<double>>(.)
.
The data can then be passed to the doSomething(.)
function in the standard C++ code base, as it is expecting a std::vector<double>
input. This function returns the C++ double
variable ret
to the variable y
in the interface function. This requires no special conversion and can be passed back to R as a C++ double
type.
Putting the High-Level Design Together
With the C++ interface in place, this means an R user can call an R function that has been exported from C++. When the results are returned, they can be used in other R functions, but where we get an extraordinarily complementary benefit is with R’s powerful data visualization capabilities. Unlike languages such as Python, Java, or VB.NET, C++ does not have a standard GUI, but we can use cutting-edge R packages such as ggplot2
, plotly
, shiny
, and xts
– among many others – to generate a massive variety of plots and visualizations that are simply not available in other general purpose languages.
Next Steps
This concludes our discussion of high-level design considerations. Coming next, we will look at examples of writing actual interface functions to simple, but real, standard C++ functions and classes.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.