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.
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:
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.
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
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
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++
ret to the variable
y in the interface function. This requires no special conversion and can be passed back to R as a C++
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
xts – among many others – to generate a massive variety of plots and visualizations that are simply not available in other general purpose languages.
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.