RCPP Jss 2011
RCPP Jss 2011
Abstract
The Rcpp package simplifies integrating C++ code with R. It provides a consistent
C++ class hierarchy that maps various types of R objects (vectors, matrices, functions,
environments, . . . ) to dedicated C++ classes. Object interchange between R and C++
is managed by simple, flexible and extensible concepts which include broad support for
C++ Standard Template Library idioms. C++ code can both be compiled, linked and
loaded on the fly, or added via packages. Flexible error and exception code handling
is provided. Rcpp substantially lowers the barrier for programmers wanting to combine
C++ code with R.
1. Introduction
R (?) is an extensible system. The ‘Writing R Extensions’ manual (?) describes in detail how
to augment R with compiled code, focusing mostly on the C language, but also mentioning
C++ and Fortran. The R application programming interface (API) described in ‘Writing R
Extensions’ is based on a set of functions and macros operating on SEXP (pointers to SEXPREC
or ‘S expression’ structures, see the ‘R Language’ manual ? for details) which are the internal
representation of R objects. In this article, we discuss the functionality of the Rcpp package
(?), which simplifies the usage of C++ code in R. Combining R and C++ is not a new idea,
so we start with a short review of other approaches and give some historical background on
the development of Rcpp.
The Rcpp package provides a consistent API for seamlessly accessing, extending or modifying
R objects at the C++ level. The API is a rewritten and extended version of an earlier API
which we refer to as the ‘classic Rcpp API’. It is still provided in the RcppClassic package
(?) to ensure compatibility, but its use is otherwise deprecated. All new development should
use the richer second API which is enclosed in the Rcpp C++ namespace, and corresponds to
the redesigned code base. This article highlights some of the key design and implementation
choices of the new API: Lightweight encapsulation of R objects in C++ classes, automatic
garbage collection strategy, code inlining, data interchange between R and C++, and error
handling.
Several examples are included to illustrate the benefits of using Rcpp as opposed to the tradi-
tional R API. Many more examples are available within the package, both as explicit examples
and as part of the numerous unit tests. The Rcpp package is available from the Comprehensive
R Archive Network (CRAN) at http://CRAN.R-project.org/package=Rcpp.
This vignette corresponds to the paper published in the Journal of Statistical Software (and is
2 Rcpp: Seamless R and C++ Integration
still mostly identical to the published paper). It had been distributed with the Rcpp package
as file Rcpp-introduction.pdf for several years but has now been superceded by an updated
introduction (??).
For citations, please use the ? or ?; details are also provided in R via citation("Rcpp").
This version corresponds to Rcpp version 1.0.8 and was typeset on January 11, 2022.
based functions. Here, we use ‘function’ in the standard mathematical sense of providing
results (output) given a set of parameters or data (input). This was facilitated from the
earliest releases using C++ classes for receiving various types of R objects, converting them
to C++ objects and allowing the programmer to return the results to R with relative ease.
This API therefore supports two typical use cases. First, existing R code may be replaced by
equivalent C++ code in order to reap performance gains. This case is conceptually easy when
there are (built- or run-time) dependencies on other C or C++ libraries. It typically involves
setting up data and parameters—the right-hand side components of a function call—before
making the call in order to provide the result that is to be assigned to the left-hand side.
Second, Rcpp facilitates calling functions provided by other libraries. The use resembles the
first case but with an additional level of abstraction: data and parameters are passed via
Rcpp to a function set-up to call code from an external library.
Apart from this ‘vertical mode’ of calling C++ from R, additional features in the new API
also support a more ‘horizontal mode’ of directly calling Rcpp objects. This was motivated by
the needs of other projects such as RInside (?) for easy embedding of R in C++ applications
and RProtoBuf (?) to interface with the Protocol Buffers library. This use will be touched
upon in the next section, but a more detailed discussion is outside the scope of this paper.
Lastly, the more recent additions ‘Rcpp modules’ and ‘Rcpp sugar’ also expand the use cases;
see Section 9 below.
#include <Rcpp.h>
return xab;
}
1. Only a single header file Rcpp.h is needed to use the Rcpp API.
4 Rcpp: Seamless R and C++ Integration
3. Given two arguments of type SEXP, a third is returned (as using only SEXP types for
input and output is prescribed by the .Call() interface of the R API).
4. Both inputs are converted to C++ vector types provided by Rcpp (and we have more
to say about these conversions below).
5. The usefulness of these classes can be seen when we query the vectors directly for
their size—using the size() member function—in order to reserve a new result type of
appropriate length, and with the use of the operator[] to extract and set individual
elements of the vector.
6. The computation itself is straightforward embedded looping just as in the original ex-
amples in the ‘Writing R Extensions’ manual (?).
7. The return conversion from the NumericVector to the SEXP type is also automatic.
We argue that this Rcpp-based usage is much easier to read, write and debug than the C
macro-based approach supported by R itself.
Using the traditional R API, the vector can be allocated and filled as such:
SEXP ab;
PROTECT(ab = allocVector(STRSXP, 2));
SET_STRING_ELT( ab, 0, mkChar("foo") );
SET_STRING_ELT( ab, 1, mkChar("bar") );
UNPROTECT(1);
Rcpp::CharacterVector ab(2);
ab[0] = "foo";
ab[1] = "bar";
The templated function takes a reference to a ‘wrappable’ object and converts this object into
a SEXP, which is what R expects. Currently wrappable types are:
• primitive types: int, double, bool, . . . which are converted into the corresponding
atomic R vectors;
• STL maps which use std::string for keys (e.g., std::map<std::string, T>); as long
as the type T is wrappable;
• any type that implements implicit conversion to SEXP through the operator SEXP();
2
A discussion of template metaprogramming (??) is beyond the scope of this article.
Dirk Eddelbuettel, Romain François 7
Wrappability of an object type is resolved at compile time using modern techniques of template
meta programming and class traits. The Rcpp-extending vignette in the Rcpp package
discusses in depth how to extend wrap to third-party types. The RcppArmadillo (?) and
RcppGSL (?) packages feature several examples. The following segment of code illustrates
that the design allows composition:
m1["foo"]=1;
m1["bar"]=2;
m2["foo"]=1;
m2["bar"]=2;
m2["baz"]=3;
v.push_back( m1 );
v.push_back( m2 );
return Rcpp::wrap( v );
}
In this example, the STL types vector and map are used to create a list of two named
vectors. The member function push_back insert a given element into a vector. This example
is equivalent to the result of this R statement:
list(c(bar = 2L, foo = 1L), c(bar = 2L, baz = 3L, foo = 1L))
3.2. R to C++: as
The reverse conversion from an R object to a C++ object is implemented by variations of the
Rcpp::as template whose signature is:
It offers less flexibility and currently handles conversion of R objects into primitive types (e.g.,
bool, int, std::string, . . . ), STL vectors of primitive types (e.g., std::vector<bool>,
std::vector<double>, . . . ) and arbitrary types that offer a constructor that takes a SEXP.
In addition as can be fully or partially specialized to manage conversion of R data structures
to third-party types as can be seen for example in the RcppArmadillo package which eases
transfer of R matrices and vectors to the optimised data structures in the Armadillo linear
algebra library (?).
In addition, the converters are also used implicitly in various places in the Rcpp API. Consider
the following code that uses the Rcpp::Environment class to interchange data between C++
and R. It accesses a vector x from the global environment, creates an STL map of string types
and pushes this back to R:
global["y"] = map;
In the first part of the example, the code extracts a std::vector<double> from the global
environment. In order to achieve this, the operator[] of Environment uses the proxy pattern
(?) to distinguish between left hand side (LHS) and right hand side (RHS) use.
The output of the operator[] is an instance of the nested class Environment::Binding.
This class defines a templated implicit conversion operator. It is this conversion operator
which allows a Binding object to be assigned to any type that Rcpp::as is able to handle.
In the last part of the example, the LHS use of the Binding instance is implemented through
its assignment operator. This is also templated and uses Rcpp::wrap to perform the conver-
sion to a SEXP that can be assigned to the requested symbol in the global environment.
The same mechanism is used throughout the API. Examples include access/modification of
object attributes, slots, elements of generic vectors (lists), function arguments, nodes of dotted
pair lists, language calls and more.
4. Function calls
The next example shows how to use Rcpp to emulate the R code rnorm(10L, sd = 100.0).
As shown in Table 1, the code can be expressed in several ways in either Rcpp or the standard
R API. The first version shows the use of the Environment and Function classes by Rcpp.
The second version shows the use of the Language class, which manages calls (LANGSXP).
For comparison, we also show both versions using the standard R API. Finally, we also show
a variant using ‘Rcpp sugar’, a topic which is discussed in Sections 8 and 9 below.
This example illustrates that the Rcpp API permits us to work with code that is easier to
read, write and maintain. More examples are available as part of the documentation included
in the Rcpp package, as well as among its over seven hundred and fifty unit tests.
Table 1: Rcpp versus the R API: Five ways of calling rnorm(10L, sd = 100) in C/C++.
Note that we have removed the Rcpp:: prefix for readability; this corresponds to adding a directive
using namespace Rcpp; in the code. The versions that use callbacks to R do not require handling
of the state of the random number generator. The version that uses Rcpp sugar requires it, which is
done via the instantiation of the RNGScope variable.
cfunction and cxxfunction. The latter provides an extension which works particularly well
with Rcpp via so-called ‘plugins’ which provide information about additional header file and
library locations.
The use of inline is possible as Rcpp can be installed and updated just like any other R
10 Rcpp: Seamless R and C++ Integration
package using, for examples, the install.packages() function for initial installation as well
as update.packages() for upgrades. So even though R/C++ interfacing would otherwise
require source code, the Rcpp library is always provided ready for use as a pre-built library
through the CRAN package mechanism.3
The library and header files provided by Rcpp for use by other packages are installed along
with the Rcpp package. The LinkingTo: Rcpp directive in the DESCRIPTION file lets R
properly reference the header files. The Rcpp package provides appropriate information for
the -L switch needed for linking via the function Rcpp:::LdFlags(). It can be used by
Makevars files of other packages, and inline makes use of it internally so that all of this is
done behind the scenes without the need for explicitly setting compiler or linker options.
The convolution example provided above can be rewritten for use by inline as shown below.
The function body is provided by the R character variable src, the function header is defined
by the argument signature, and we only need to enable plugin = "Rcpp" to obtain a new
R function fun based on the C++ code in src:
[1] 1 4 10 16 17 12
With one assignment to the R variable src, and one call of the R function cxxfunction
(provided by the inline package), we have created a new R function fun that uses the C++
code we assigned to src—and all this functionality can be used directly from the R prompt
making prototyping with C++ functions straightforward.
Update: Rcpp version 0.10.0 and later contain new and powerful feature called ’Rcpp At-
tributes’ which provides an even more powerful mechanism; see ? for more details.
All Rcpp classes from the new API representing vectors (including lists) can produce ranges
through their member functions begin() and end(), effectively supporting iterating over
elements of an R vector.
The following code illustrates how Rcpp might be used to emulate a simpler4 version of lapply
using the transform algorithm from the STL.
We can now use this cpp_lapply function to calculate a summary of each column of the
faithful data set included with R.
$eruptions
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.600 2.163 4.000 3.488 4.454 5.100
$waiting
Min. 1st Qu. Median Mean 3rd Qu. Max.
43.0 58.0 76.0 70.9 82.0 96.0
7. Error handling
Code that uses both R and C++ has to deal with two distinct error handling models. Rcpp
simplifies this and allows both systems to work together.
The macros are simply defined to avoid code repetition. They expand to simple try/catch
blocks so that the above example becomes:
Using BEGIN_RCPP and END_RCPP—or the expanded versions—guarantees that the stack is
first unwound in terms of C++ exceptions, before the problem is converted to the standard
R error management system using the function Rf_error of the R API.
The forward_exception_to_r function uses run-time type information to extract informa-
tion about the class of the C++ exception and its message so that dedicated handlers can be
installed on the R side.
A serious limitation of this approach is the lack of support for calling handlers. R calling
handlers are also based on POSIX jumps, and using both calling handlers from the R engine
as well C++ exception forwarding might lead to undetermined results. Future versions of
Rcpp might attempt to to improve this issue.
Dirk Eddelbuettel, Romain François 13
8. Performance comparison
In this section, we present several different ways to leverage Rcpp to rewrite the convolution
example from ‘Writing R Extensions’ (?, Chapter 5) first discussed in Section 2. As part of
the redesign of Rcpp, data copy is kept to the absolute minimum: The RObject class and
all its derived classes are just a container for a SEXP object. We let R perform all memory
management and access data though the macros or functions offered by the standard R API.
The implementation of the operator[] is designed to be as efficient as possible, using both
inlining and caching, but even this implementation is still less efficient than the reference C
implementation described in ?.
Rcpp follows design principles from the STL, and classes such as NumericVector expose
iterators that can be used for sequential scans of the data. Algorithms using iterators are
usually more efficient than those that operate on objects using the operator[]. The following
version of the convolution function illustrates the use of the NumericVector::iterator.
#include <Rcpp.h>
return xab;
}
14 Rcpp: Seamless R and C++ Integration
One of the focuses of recent developments of Rcpp is called ‘Rcpp sugar’, and aims to provide
R-like syntax in C++. While a fuller discussion of Rcpp sugar is beyond the scope of this
article, we have included another version of the convolution algorithm based on Rcpp sugar
for illustrative purposes here:
#include <Rcpp.h>
Rcpp::Range r( 0, n_xb-1 );
for (int i=0; i<n_xa; i++, r++)
xab[ r ] += Rcpp::noNA(xa[i]) * Rcpp::noNA(xb);
return xab ;
}
Rcpp sugar allows manipulation of entire subsets of vectors at once, thanks to the Range
class. Rcpp sugar uses techniques such as expression templates, lazy evaluation and loop
unrolling to generate very efficient code. The noNA template function marks its argument
to indicates that it does not contain any missing values—an assumption made implicitly by
other versions—allowing sugar to compute the individual operations without having to test
for missing values.
We have benchmarked the various implementations by averaging over 5000 calls of each
function with a and b containing 200 elements each.5 The timings are summarized in Table 2
below.
The first implementation, written in C and using the traditional R API, provides our base
case. It takes advantage of pointer arithmetics and therefore does not to pay the price of
C++ object encapsulation or operator overloading.
The slowest solution illustrates the price of object encapsulation. Calling an overloaded
operator[] as opposed to using direct pointer arithmetics as in the reference case costs
about 29% in performance.
The next implementation uses iterators rather than indexing. Its performance is indistin-
guishable from the base case. This also shows that the use of C++ may not necessarily imply
any performance penalty. Further, C++ iterators can be used to achieve the performance
of C pointers, but without the potential dangers of direct memory access via pointers.
Finally, the fastest implementation uses Rcpp sugar. It performs significantly better than the
base case. Explicit loop unrolling provides us with vectorization at the C++ level which is
responsible for this particular speedup.
9. On-going development
5
The code is contained in the directory inst/examples/ConvolveBenchmarks in the Rcpp package.
Dirk Eddelbuettel, Romain François 15
Rcpp is in very active development: Current work in the package (and in packages such as
RcppArmadillo) focuses on further improving interoperability between R and C++. Two core
themes for on-going development are ‘Rcpp sugar’ as well as ‘Rcpp modules’, both of which
are also discussed in more detail in specific vignettes in the Rcpp package.
‘Rcpp sugar’ offers syntactic sugar at the C++ level, including optimized binary operators and
many R functions such as ifelse, sapply, any, head, tail, and more. The main technique
used in Rcpp sugar is expression templates pioneered by the Blitz++ library (?) and since
adopted by projects such as Armadillo (?). Access to most of the d/p/q/r-variants of the
statistical distribution functions has also been added, enabling the use of expressions such
as dnorm(X, m, s) for a numeric vector X and scalars m and s. This was shown in Table 1
in Section 4 above where the R expression rnorm(10L, sd = 100) was rewritten in C++
as rnorm(10, 0, 100). Note that C++ semantics require the second parameter to be used
here, which is different from the R case.
‘Rcpp modules’ allows programmers to expose C++ functions and classes at the R level. This
offers access to C++ code from R using even less interface code than by writing accessor
functions. Modules are inspired by the Boost.Python library (?) which provides similar
functionality for Python. C++ classes exposed by Rcpp modules are shadowed by reference
classes which have been introduced in R 2.12.0.
Update: Besides the vignettes for ’Rcpp Sugar’ (?) and ’Rcpp Modules’ (?), the aforemen-
tioned vignette for ’Rcpp Attributes’ (?) describes a new possibility for even more direct
integration between Rcpp and C++.
10. Summary
The Rcpp package presented in this paper greatly simplifies integration of compiled C++
code with R. Rcpp provides a C++ class hierarchy which allows manipulation of R data
structures in C++ using member functions and operators directly related to the type of object
being used, thereby reducing the level of expertise required to master the various functions
and macros offered by the internal R API. The classes assume the entire responsibility of
garbage collection of objects, relieving the programmer from book-keeping operations with
the protection stack and enabling him/her to focus on the underlying problem.
Data interchange between R and C++ code is performed by the wrap() and as() template
functions. They allow the programmer to write logic in terms of C++ data structures,
and facilitate use of modern libraries such as the Standard Template Library (STL) and
its containers and algorithms. The wrap() and as() template functions are extensible by
design. They are also used either explicitly or implicitly throughout the API. By using only
16 Rcpp: Seamless R and C++ Integration
thin wrappers around SEXP objects and adopting C++ idioms such as iterators, the footprint
of the Rcpp API is very lightweight, and does not incur a significant performance penalty.
The Rcpp API offers opportunities to dramatically reduce the complexity of code, which
should lower the initial cost of writing code and improve code readability, maintainability,
and reuse—without incurring noticeable penalties in run-time performance.
Acknowledgments
Detailed comments and suggestions by editors as well as anonymous referees are gratefully
acknowledged. We are also thankful for code contributions by Douglas Bates and John Cham-
bers, as well as for very helpful suggestions by Uwe Ligges, Brian Ripley and Simon Urbanek
concerning the build systems for different platforms. Last but not least, several users provided
very fruitful ideas for new or extended features via the rcpp-devel mailing list.
References
Armstrong W (2009a). RAbstraction: C++ abstraction for R objects. Code repository last
updated 2009-07-22., URL https://github.com/armstrtw/rabstraction.
Bates DM, DebRoy S (2001). “C++ Classes for R Objects.” In K Hornik, F Leisch (eds.),
Proceedings of the 2nd International Workshop on Distributed Statistical Computing, March
15–17, 2001, Technische Universität Wien, Vienna, Austria. ISSN 1609-395X, URL https:
//www.ci.tuwien.ac.at/Conferences/DSC-2001/Proceedings/.
Eddelbuettel D (2013). Seamless R and C++ Integration with Rcpp. Use R! Springer, New
York. ISBN 978-1-4614-6867-7.
R Core Team (2021b). R internals. R Foundation for Statistical Computing, Vienna, Austria.
URL https://CRAN.R-Project.org/doc/manuals/R-ints.html.
R Core Team (2021c). R language. R Foundation for Statistical Computing, Vienna, Austria.
URL https://CRAN.R-Project.org/doc/manuals/R-lang.html.
R Core Team (2021d). Writing R extensions. R Foundation for Statistical Computing, Vienna,
Austria. URL https://CRAN.R-Project.org/doc/manuals/R-exts.html.
Sanderson C (2010). “Armadillo: An open source C++ Algebra Library for Fast Prototyping
and Computationally Intensive Experiments.” Technical report, NICTA. URL https:
//arma.sf.net.
Temple Lang D (2009a). “A modest proposal: an approach to making the internal R system
extensible.” Computational Statistics, 24(2), 271–281.
Temple Lang D (2009b). “Working with meta-data from C/C++ code in R: the RGCCTrans-
lationUnit package.” Computational Statistics, 24(2), 283–293.
Urbanek S (2021). Rserve: Binary R server. R package version 1.8-10, URL https://CRAN.
R-Project.org/package=Rserve.
Veldhuizen TL (1998). “Arrays in Blitz++.” In ISCOPE ’98: Proceedings of the Second Inter-
national Symposium on Computing in Object-Oriented Parallel Environments, pp. 223–230.
Springer-Verlag, London. ISBN 3-540-65387-2.
Affiliation:
Dirk Eddelbuettel
Debian Project
River Forest, IL, United States of America
E-mail: edd@debian.org
URL: http://dirk.eddelbuettel.com/
Dirk Eddelbuettel, Romain François 19
Romain François
Professional R Enthusiast
1 rue du Puits du Temple
34 000 Montpellier, France
E-mail: romain@r-enthusiasts.com
URL: http://romainfrancois.blog.free.fr/