1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
|
\documentclass[10pt]{article}
%\VignetteIndexEntry{Rcpp-modules}
%\VignetteEngine{highlight::highlight}
%\VignetteKeywords{Rcpp, module}
%\VignetteDepends{Rcpp}
\usepackage[USletter]{vmargin}
\setmargrb{0.75in}{0.75in}{0.75in}{0.75in}
\usepackage{color, alltt}
\usepackage[authoryear,round,longnamesfirst]{natbib}
\usepackage[colorlinks]{hyperref}
\definecolor{link}{rgb}{0,0,0.3} %% next few lines courtesy of RJournal.sty
\hypersetup{
colorlinks,%
citecolor=link,%
filecolor=link,%
linkcolor=link,%
urlcolor=link
}
\usepackage{microtype} %% cf http://www.khirevich.com/latex/microtype/
\usepackage[T1]{fontenc} %% cf http://www.khirevich.com/latex/font/
\usepackage[bitstream-charter]{mathdesign} %% cf http://www.khirevich.com/latex/font/
\newcommand{\code}[1]{\texttt{#1}}
\newcommand{\proglang}[1]{\textsf{#1}}
\newcommand{\pkg}[1]{{\fontseries{b}\selectfont #1}}
%% This corresponds to setting boxes=TRUE for highlight
\newsavebox{\hlbox}
\definecolor{hlBg}{rgb}{0.949019607843137,0.949019607843137,0.949019607843137}
\definecolor{hlBd}{rgb}{0,0,0}
\renewenvironment{Hchunk}{\vspace{0.5em}\noindent\begin{lrbox}{\hlbox}\begin{minipage}[b]{.9\textwidth}}%
{\end{minipage}\end{lrbox}\fcolorbox{hlBd}{hlBg}{\usebox{\hlbox}}\vspace{0.5em}}
<<echo=FALSE,print=FALSE>>=
suppressMessages(require(Rcpp))
prettyVersion <- packageDescription("Rcpp")$Version
prettyDate <- format(Sys.Date(), "%B %e, %Y")
@
\author{Dirk Eddelbuettel \and Romain Fran\c{c}ois}
\title{Exposing \proglang{C++} functions and classes with \pkg{Rcpp} modules}
\date{\pkg{Rcpp} version \Sexpr{prettyVersion} as of \Sexpr{prettyDate}}
\begin{document}
\maketitle
\abstract{
\noindent
This note discusses \textsl{Rcpp modules}. \textsl{Rcpp modules} allow programmers to
expose \proglang{C++} functions and classes to \proglang{R} with relative
ease. \textsl{Rcpp modules} are inspired from the \pkg{Boost.Python}
\proglang{C++} library \citep{Abrahams+Grosse-Kunstleve:2003:Boost.Python}
which provides similar features for \proglang{Python}.
}
\section{Motivation}
Exposing \proglang{C++} functionality to \proglang{R} is greatly facilitated
by the \pkg{Rcpp} package and its underlying \proglang{C++} library
\citep{CRAN:Rcpp,JSS:Rcpp}. \pkg{Rcpp} smoothes many of the rough edges in
\proglang{R} and \proglang{C++} integration by replacing the traditional
\proglang{R} Application Programming Interface (API) described in
`\textsl{Writing R Extensions}' \citep{R:Extensions} with a consistent set of \proglang{C++}
classes. The `\textsl{Rcpp-introduction}' vignette \citep{CRAN:Rcpp,JSS:Rcpp} describes the API and
provides an introduction to using \pkg{Rcpp}.
These \pkg{Rcpp} facilities offer a lot of assistance to the programmer
wishing to interface \proglang{R} and \proglang{C++}. At the same time, these
facilities are limited as they operate on a function-by-function basis. The
programmer has to implement a \code{.Call} compatible function (to
conform to the \proglang{R} API) using classes of the \pkg{Rcpp} API as
described in the next section.
\subsection{Exposing functions using \pkg{Rcpp}}
Exposing existing \proglang{C++} functions to \proglang{R} through \pkg{Rcpp}
usually involves several steps. One approach is to write an additional wrapper
function that is responsible for converting input objects to the appropriate
types, calling the actual worker function and converting the results back to
a suitable type that can be returned to \proglang{R} (\texttt{SEXP}).
Consider the \texttt{norm} function below:
<<lang=cpp>>=
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
@
This simple function does not meet the requirements set by the \texttt{.Call}
convention, so it cannot be called directly by \proglang{R}. Exposing the
function involves writing a simple wrapper function
that does match the \texttt{.Call} requirements. \pkg{Rcpp} makes this easy.
<<lang=cpp>>=
using namespace Rcpp;
RcppExport SEXP norm_wrapper(SEXP x_, SEXP y_) {
// step 0: convert input to C++ types
double x = as<double>(x_), y = as<double>(y_);
// step 1: call the underlying C++ function
double res = norm( x, y );
// step 2: return the result as a SEXP
return wrap( res );
}
@
Here we use the (templated) \pkg{Rcpp} converter \texttt{as()} which can
transform from a \texttt{SEXP} to a number of different \proglang{C++} and
\pkg{Rcpp} types. The \pkg{Rcpp} function \texttt{wrap()} offers the opposite
functionality and converts many known types to a \texttt{SEXP}.
This process is simple enough, and is used by a number of CRAN packages.
However, it requires direct involvement from the programmer, which quickly
becomes tiresome when many functions are involved. \textsl{Rcpp modules}
provides a much more elegant and unintrusive way to expose \proglang{C++}
functions such as the \texttt{norm} function shown above to \proglang{R}.
We should note that \pkg{Rcpp} now has \textsl{Rcpp attributes} which extends
certain aspect of \textsl{Rcpp modules} and makes binding to simple functions
such as this one even easier. With \textsl{Rcpp attribues} we can just write
<<lang=cpp>>=
# include <Rcpp.h>
// [[Rcpp::export]]
double norm(double x, double y) {
return sqrt(x*x + y*y);
}
@
See the corresponding vignette \citep{CRAN:Rcpp:Attributes} for details, but
read on for \textsl{Rcpp modules} which contains to provide features not
covered by \textsl{Rcpp attributes}, particularly when it comes to binding
entire C++ classes and more.
\subsection{Exposing classes using Rcpp}
Exposing \proglang{C++} classes or structs is even more of a challenge because it
requires writing glue code for each member function that is to be exposed.
Consider the simple \texttt{Uniform} class below:
<<lang=cpp>>=
class Uniform {
public:
Uniform(double min_, double max_) : min(min_), max(max_) {}
NumericVector draw(int n) {
RNGScope scope;
return runif( n, min, max );
}
private:
double min, max;
};
@
To use this class from R, we at least need to expose the constructor and
the \texttt{draw} method. External pointers
\citep{R:Extensions} are the perfect vessel for this, and using the
\texttt{Rcpp:::XPtr} template from \pkg{Rcpp} we can expose the class
with these two functions:
<<lang=cpp>>=
using namespace Rcpp;
/// create an external pointer to a Uniform object
RcppExport SEXP Uniform__new(SEXP min_, SEXP max_) {
// convert inputs to appropriate C++ types
double min = as<double>(min_), max = as<double>(max_);
// create a pointer to an Uniform object and wrap it
// as an external pointer
Rcpp::XPtr<Uniform> ptr( new Uniform( min, max ), true );
// return the external pointer to the R side
return ptr;
}
/// invoke the draw method
RcppExport SEXP Uniform__draw( SEXP xp, SEXP n_ ) {
// grab the object as a XPtr (smart pointer) to Uniform
Rcpp::XPtr<Uniform> ptr(xp);
// convert the parameter to int
int n = as<int>(n_);
// invoke the function
NumericVector res = ptr->draw( n );
// return the result to R
return res;
}
@
As it is generally a bad idea to expose external pointers `as is',
they usually get wrapped as a slot of an S4 class.
Using \code{cxxfunction()} from the \pkg{inline} package, we can build this
example on the fly. Suppose the previous example code assigned to a text variable
\texttt{unifModcode}, we could then do
%% DE 21 Sep 2013: there must a bug somewhere in the vignette processing
%% as the following example produces only empty lines preceded
%% by '+' -- same for 0.10.4 release and current 0.10.5 pre-release
%% hence shortened example to not show code again
<<eval=FALSE>>=
f1 <- cxxfunction( , "", includes = unifModCode, plugin = "Rcpp" )
getDynLib(f1) ## will display information about 'f1' just created
@
The following listing shows some \textsl{manual} wrapping to access the code,
we will see later how this can be automated:
<<eval=FALSE>>=
setClass( "Uniform", representation( pointer = "externalptr" ) )
# helper
Uniform_method <- function(name) {
paste( "Uniform", name, sep = "__" )
}
# syntactic sugar to allow object$method( ... )
setMethod( "$", "Uniform", function(x, name ) {
function(...) .Call( Uniform_method(name) , x@pointer, ... )
} )
# syntactic sugar to allow new( "Uniform", ... )
setMethod( "initialize", "Uniform", function(.Object, ...) {
.Object@pointer <- .Call( Uniform_method("new"), ... )
.Object
} )
u <- new( "Uniform", 0, 10 )
u$draw( 10L )
@
\pkg{Rcpp} considerably simplifies the code that would
be involved for using external pointers with the traditional \proglang{R} API.
Yet this still involves a lot of mechanical code that quickly
becomes hard to maintain and error prone.
\textsl{Rcpp modules} offer an elegant way to expose the \texttt{Uniform}
class in a way that makes both the internal
\proglang{C++} code and the \proglang{R} code easier.
\section{Rcpp modules}
\label{sec:modules}
The design of Rcpp modules has been influenced by \proglang{Python} modules which are generated by the
\texttt{Boost.Python} library \citep{Abrahams+Grosse-Kunstleve:2003:Boost.Python}.
Rcpp modules provide a convenient and easy-to-use way
to expose \proglang{C++} functions and classes to \proglang{R}, grouped
together in a single entity.
A Rcpp module is created in a \texttt{cpp} file using the \texttt{RCPP\_MODULE}
macro, which then provides declarative code of what the module
exposes to \proglang{R}.
\subsection{Exposing \proglang{C++} functions using Rcpp modules}
Consider the \texttt{norm} function from the previous section.
We can expose it to \proglang{R} :
<<lang=cpp>>=
using namespace Rcpp;
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
RCPP_MODULE(mod) {
function( "norm", &norm );
}
@
The code creates an Rcpp module called \texttt{mod}
that exposes the \texttt{norm} function. \pkg{Rcpp} automatically
deduces the conversions that are needed for input and output. This alleviates
the need for a wrapper function using either \pkg{Rcpp} or the \proglang{R} API.
On the \proglang{R} side, the module is retrieved by using the
\code{Module} function from \pkg{Rcpp}
<<eval=FALSE>>=
inc <- '
using namespace Rcpp;
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
RCPP_MODULE(mod) {
function( "norm", &norm );
}
'
fx <- cxxfunction(signature(), plugin="Rcpp", include=inc)
mod <- Module("mod", getDynLib(fx))
@
Note that this example assumed that the previous code segment defining the
module was returned by the \code{cxxfunction()} (from the \pkg{inline}
package) as callable R function \code{fx} from which we can extract the
relevant pointer using \code{getDynLib()}. In the case of using Rcpp modules
via a package (which is detailed in Section~\ref{sec:package} below), modules
are actually loaded differently and we would have used
<<eval=FALSE>>=
require(nameOfMyModulePackage)
mod <- new( mod )
mod$norm( 3, 4 )
@
where the module is loaded upon startup and we use the constructor
directly. More details on this aspect follow below.
A module can contain any number of calls to \texttt{function} to register
many internal functions to \proglang{R}. For example, these 6 functions :
<<lang=cpp>>=
std::string hello() {
return "hello";
}
int bar( int x) {
return x*2;
}
double foo( int x, double y) {
return x * y;
}
void bla( ) {
Rprintf( "hello\\n" );
}
void bla1( int x) {
Rprintf( "hello (x = %d)\\n", x );
}
void bla2( int x, double y) {
Rprintf( "hello (x = %d, y = %5.2f)\\n", x, y );
}
@
can be exposed with the following minimal code:
<<lang=cpp>>=
RCPP_MODULE(yada) {
using namespace Rcpp;
function("hello" , &hello);
function("bar" , &bar );
function("foo" , &foo );
function("bla" , &bla );
function("bla1" , &bla1 );
function("bla2" , &bla2 );
}
@
which can then be used from \proglang{R}:
<<eval=FALSE>>=
require( Rcpp )
yd <- Module("yada", getDynLib(fx))
yd$bar(2L)
yd$foo(2L, 10.0)
yd$hello()
yd$bla()
yd$bla1(2L)
yd$bla2(2L, 5.0)
@
In the case of a package (as for example the one created by
\code{Rcpp.package.skeleton()} with argument \code{module=TRUE}; more on that
below), we can use
<<eval=FALSE>>=
require(myModulePackage) ## or whichever name was chose
bar(2L)
foo(2L, 10.0)
hello()
bla()
bla1(2L)
bla2(2L, 5.0)
@
The requirements for a function to be exposed to \proglang{R} via Rcpp modules
are:
\begin{itemize}
\item The function takes between 0 and 65 parameters.
\item The type of each input parameter must be manageable by the \texttt{Rcpp::as}
template.
\item The return type of the function must be either \texttt{void} or any type that
can be managed by the \texttt{Rcpp::wrap} template.
\item The function name itself has to be unique in the module.
In other words, no two functions with
the same name but different signatures are allowed. C++ allows overloading
functions. This might be added in future versions of modules.
\end{itemize}
\subsubsection{Documentation for exposed functions using Rcpp modules}
In addition to the name of the function and the function pointer, it is possible
to pass a short description of the function as the third parameter of \texttt{function}.
<<lang=cpp>>=
using namespace Rcpp;
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
RCPP_MODULE(mod) {
function( "norm", &norm, "Provides a simple vector norm" );
}
@
The description is used when displaying the function to the R prompt:
<<eval=FALSE>>=
mod <- Module("mod", getDynLib(fx))
show(mod$norm)
@
\subsubsection{Formal arguments specification}
\texttt{function} also gives the possibility to specify the formal arguments
of the R function that encapsulates the C++ function, by passing
a \texttt{Rcpp::List} after the function pointer.
<<lang=cpp>>=
using namespace Rcpp;
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
RCPP_MODULE(mod_formals) {
function("norm",
&norm,
List::create( _["x"] = 0.0, _["y"] = 0.0 ),
"Provides a simple vector norm");
}
@
A simple usage example is provided below:
<<eval=FALSE>>=
norm <- mod$norm
norm()
norm( y = 2 )
norm( x = 2, y = 3 )
args( norm )
@
To set formal arguments without default values, simply omit the rhs.
<<lang=cpp>>=
using namespace Rcpp;
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
RCPP_MODULE(mod_formals2) {
function("norm", &norm,
List::create( _["x"], _["y"] = 0.0 ),
"Provides a simple vector norm");
}
@
This can be used as follows:
<<eval=FALSE>>=
norm <- mod$norm
args(norm)
@
The ellipsis (\texttt{...}) can be used to denote that additional arguments
are optional; it does not take a default value.
<<lang=cpp>>=
using namespace Rcpp;
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
RCPP_MODULE(mod_formals3) {
function( "norm", &norm,
List::create( _["x"], _["..."] ),
"documentation for norm");
}
@
<<eval=FALSE>>=
norm <- mod$norm
args( norm )
@
\subsection{Exposing \proglang{C++} classes using Rcpp modules}
Rcpp modules also provide a mechanism for exposing \proglang{C++} classes, based
on the reference classes introduced in R 2.12.0.
\subsubsection{Initial example}
A class is exposed using the \texttt{class\_} keyword. The \texttt{Uniform}
class may be exposed to \proglang{R} as follows:
<<lang=cpp>>=
using namespace Rcpp;
class Uniform {
public:
Uniform(double min_, double max_) : min(min_), max(max_) {}
NumericVector draw(int n) const {
RNGScope scope;
return runif( n, min, max );
}
double min, max;
};
double uniformRange( Uniform* w) {
return w->max - w->min;
}
RCPP_MODULE(unif_module) {
class_<Uniform>( "Uniform" )
.constructor<double,double>()
.field( "min", &Uniform::min )
.field( "max", &Uniform::max )
.method( "draw", &Uniform::draw )
.method( "range", &uniformRange )
;
}
@
<<eval=FALSE>>=
## assumes fx_unif <- cxxfunction(...) has ben run
unif_module <- Module( "unif_module", getDynLib(fx_unif ) )
Uniform <- unif_module$Uniform
u <- new( Uniform, 0, 10 )
u$draw( 10L )
u$range()
u$max <- 1
u$range()
u$draw( 10 )
@
\texttt{class\_} is templated by the \proglang{C++} class or struct
that is to be exposed to \proglang{R}.
The parameter of the \texttt{class\_<Uniform>} constructor is the name we will
use on the \proglang{R} side. It usually makes sense to use the same name as the class
name. While this is not enforced, it might be useful when exposing a class
generated from a template.
Then constructors, fields and methods are exposed.
\subsubsection{Exposing constructors using Rcpp modules}
Public constructors that take from 0 and 6 parameters can be exposed
to the R level using the \texttt{.constuctor} template method of \texttt{.class\_}.
Optionally, \texttt{.constructor} can take a description as the first argument.
<<lang=cpp>>=
.constructor<double,double>("sets the min and max value of the distribution")
@
Also, the second argument can be a function pointer (called validator)
matching the following type :
<<lang=cpp>>=
typedef bool (*ValidConstructor)(SEXP*,int);
@
The validator can be used to implement dispatch to the appropriate constructor,
when multiple constructors taking the same number of arguments are exposed.
The default validator always accepts the constructor as valid if it is passed
the appropriate number of arguments. For example, with the call above, the default
validator accepts any call from R with two \texttt{double} arguments (or
arguments that can be cast to \texttt{double}).
TODO: include validator example here
\subsubsection{Exposing fields and properties}
\texttt{class\_} has three ways to expose fields and properties, as
illustrated in the example below :
<<lang=cpp>>=
using namespace Rcpp;
class Foo {
public:
Foo(double x_, double y_, double z_ ):
x(x_), y(y_), z(z_) {}
double x;
double y;
double get_z() { return z; }
void set_z( double z_ ) { z = z_; }
private:
double z;
};
RCPP_MODULE(mod_foo) {
class_<Foo>( "Foo" )
.constructor<double,double,double>()
.field( "x", &Foo::x )
.field_readonly( "y", &Foo::y )
.property( "z", &Foo::get_z, &Foo::set_z )
;
}
@
The \texttt{.field} method exposes a public field with read/write access from R.
\texttt{field} accepts an extra parameter to give a short description of the
field:
<<lang=cpp>>=
.field( "x", &Foo::x, "documentation for x" )
@
The \texttt{.field\_readonly} exposes a public field with read-only access from R.
It also accepts the description of the field.
<<lang=cpp>>=
.field_readonly( "y", &Foo::y, "documentation for y" )
@
The \texttt{.property} method allows indirect access to fields through
a getter and a setter. The setter is optional, and the property is considered
read-only if the setter is not supplied. A description of the property is also
allowed:
<<lang=cpp>>=
// with getter and setter
.property( "z", &Foo::get_z, &Foo::set_z, "Documentation for z" )
// with only getter
.property( "z", &Foo::get_z, "Documentation for z" )
@
The type of the field (\textbf{T}) is deduced from the return type of the getter, and if a
setter is given its unique parameter should be of the same type.
Getters can be member functions taking no parameter and returning a \textbf{T}
(for example \texttt{get\_z} above), or
a free function taking a pointer to the exposed
class and returning a \textbf{T}, for example:
<<lang=cpp>>=
double z_get( Foo* foo ) { return foo->get_z(); }
@
Setters can be either a member function taking a \texttt{T} and returning void, such
as \texttt{set\_z} above, or a free function taking a pointer to the target
class and a \textbf{T} :
<<lang=cpp>>=
void z_set( Foo* foo, double z ) { foo->set_z(z); }
@
Using properties gives more flexibility in case field access has to be tracked
or has impact on other fields. For example, this class keeps track of how many times
the \texttt{x} field is read and written.
<<lang=cpp>>=
class Bar {
public:
Bar(double x_) : x(x_), nread(0), nwrite(0) {}
double get_x( ) {
nread++;
return x;
}
void set_x( double x_) {
nwrite++;
x = x_;
}
IntegerVector stats() const {
return IntegerVector::create(_["read"] = nread,
_["write"] = nwrite);
}
private:
double x;
int nread, nwrite;
};
RCPP_MODULE(mod_bar) {
class_<Bar>( "Bar" )
.constructor<double>()
.property( "x", &Bar::get_x, &Bar::set_x )
.method( "stats", &Bar::stats )
;
}
@
Here is a simple usage example:
<<eval=FALSE>>=
Bar <- mod_bar$Bar
b <- new( Bar, 10 )
b$x + b$x
b$stats()
b$x <- 10
b$stats()
@
\subsubsection{Exposing methods using Rcpp modules}
\texttt{class\_} has several overloaded and templated \texttt{.method}
functions allowing the programmer to expose a method associated with the class.
A legitimate method to be exposed by \texttt{.method} can be:
\begin{itemize}
\item A public member function of the class, either const or non const, that
returns void or any type that can be handled by \texttt{Rcpp::wrap}, and that
takes between 0 and 65 parameters whose types can be handled by \texttt{Rcpp::as}.
\item A free function that takes a pointer to the target class as its first
parameter, followed by 0 or more (up to 65) parameters that can be handled by
\texttt{Rcpp::as} and returning a type that can be handled by \texttt{Rcpp::wrap}
or void.
\end{itemize}
\paragraph{Documenting methods} \texttt{.method} can also include
a short documentation of the method, after the
method (or free function) pointer.
<<lang=cpp>>=
.method("stats", &Bar::stats,
"vector indicating the number of times x has been read and written" )
@
TODO: mention overloading, need good example.
\paragraph{Const and non-const member functions}
\texttt{method} is able to expose both \texttt{const} and \texttt{non const}
member functions of a class. There are however situations where
a class defines two versions of the same method, differing only in their
signature by the \texttt{const}-ness. It is for example the case of the
member functions \texttt{back} of the \texttt{std::vector} template from
the STL.
<<lang=cpp>>=
reference back ( );
const_reference back ( ) const;
@
To resolve the ambiguity, it is possible to use \texttt{const\_method}
or \texttt{nonconst\_method} instead of \texttt{method} in order
to restrict the candidate methods.
\paragraph{Special methods}
\pkg{Rcpp} considers the methods \texttt{[[} and \texttt{[[<-} special,
and promotes them to indexing methods on the \proglang{R} side.
\subsubsection{Object finalizers}
The \texttt{.finalizer} member function of \texttt{class\_} can be used to
register a finalizer. A finalizer is a free function that takes a pointer
to the target class and return \texttt{void}. The finalizer is called
before the destructor and so operates on a valid object of the target class.
It can be used to perform operations, releasing resources, etc ...
The finalizer is called automatically when the \proglang{R} object that encapsulates
the \proglang{C++} object is garbage collected.
\subsubsection{S4 dispatch}
When a \proglang{C++} class is exposed by the \texttt{class\_} template,
a new S4 class is registered as well. The name of the S4 class is
obfuscated in order to avoid name clashes (i.e. two modules exposing the
same class).
This allows implementation of \proglang{R}-level
(S4) dispatch. For example, one might implement the \texttt{show}
method for \proglang{C++} \texttt{World} objects:
<<eval=FALSE>>=
setMethod( "show", yada$World , function(object) {
msg <- paste( "World object with message : ", object$greet() )
writeLines( msg )
} )
@
TODO: mention R inheritance (John ?)
\subsubsection{Full example}
% TODO: maybe replace this by something from wls or RcppModels ?
The following example illustrates how to use Rcpp modules to expose
the class \texttt{std::vector<double>} from the STL.
<<lang=cpp>>=
typedef std::vector<double> vec; // convenience typedef
void vec_assign( vec* obj, Rcpp::NumericVector data ) { // helpers
obj->assign( data.begin(), data.end() );
}
void vec_insert( vec* obj, int position, Rcpp::NumericVector data) {
vec::iterator it = obj->begin() + position;
obj->insert( it, data.begin(), data.end() );
}
Rcpp::NumericVector vec_asR( vec* obj ) { return Rcpp::wrap( *obj ); }
void vec_set( vec* obj, int i, double value ) { obj->at( i ) = value; }
RCPP_MODULE(mod_vec) {
using namespace Rcpp;
// we expose the class std::vector<double> as "vec" on the R side
class_<vec>( "vec")
// exposing constructors
.constructor()
.constructor<int>()
// exposing member functions
.method( "size", &vec::size)
.method( "max_size", &vec::max_size)
.method( "resize", &vec::resize)
.method( "capacity", &vec::capacity)
.method( "empty", &vec::empty)
.method( "reserve", &vec::reserve)
.method( "push_back", &vec::push_back )
.method( "pop_back", &vec::pop_back )
.method( "clear", &vec::clear )
// specifically exposing const member functions
.const_method( "back", &vec::back )
.const_method( "front", &vec::front )
.const_method( "at", &vec::at )
// exposing free functions taking a std::vector<double>*
// as their first argument
.method( "assign", &vec_assign )
.method( "insert", &vec_insert )
.method( "as.vector", &vec_asR )
// special methods for indexing
.const_method( "[[", &vec::at )
.method( "[[<-", &vec_set )
;
}
@
<<eval=FALSE>>=
## for code compiled on the fly using cxxfunction() into 'fx_vec', we use
mod_vec <- Module( "mod_vec", getDynLib(fx_vec), mustStart = TRUE )
vec <- mod_vec$vec
## and that is not needed in a package setup as e.g. one created
## via Rcpp.package.skeleton(..., module=TRUE)
v <- new( vec )
v$reserve( 50L )
v$assign( 1:10 )
v$push_back( 10 )
v$size()
v$capacity()
v[[ 0L ]]
v$as.vector()
@
\section{Using modules in other packages}
\label{sec:package}
\subsection{Namespace import/export}
\subsubsection{Import all functions and classes}
When using \pkg{Rcpp} modules in a packages, the client package needs to
import \pkg{Rcpp}'s namespace. This is achieved by adding the
following line to the \texttt{NAMESPACE} file.
<<echo=FALSE,eval=TRUE>>=
options( prompt = " ", continue = " " )
@
<<eval=FALSE>>=
import( Rcpp )
@
The simplest way to load all functions and classes from a module directly
into a package namespace is to use the \code{loadRcppModules} function
within the \code{.onLoad} body.
<<eval=FALSE>>=
.onLoad <- function(libname, pkgname) {
loadRcppModules()
}
@
This will look in the package's DESCRIPTION file for the \texttt{RcppModules}
field, load each declared module and populate their contents into the
package's namespace. For example, both the \pkg{testRcppModule} package
(which is part of large unit test suite for \pkg{Rcpp}) and the package
created via \code{Rcpp.package.skeleton("somename", module=TRUE)} have this
declaration:
\begin{verbatim}
RcppModules: yada, stdVector, NumEx
\end{verbatim}
The \code{loadRcppModules} function has a single argument \texttt{direct}
with a default value of \texttt{TRUE}. With this default value, all content
from the module is exposed directly in the package namespace. If set to
\texttt{FALSE}, all content is exposed as components of the module.
Starting with release 0.9.11, an alternative is provided by the
\code{loadModule()} function which takes the module name as an argument.
It can be placed in any \code{.R} file in the package. This is useful as it allows to load
the module from the same file as some auxiliary \proglang{R} functions using the
module. For the example module, the equivalent code to the \code{.onLoad()}
use shown above then becomes
<<eval=FALSE>>=
loadModule("yada")
loadModule("stdVector")
loadModule("NumEx")
@
This feature is also used in the new Rcpp Classes introduced with Rcpp 0.9.11.
\subsubsection{Just expose the module}
Alternatively, it is possible to just expose the module to the user of the package,
and let them extract the functions and classes as needed. This uses lazy loading
so that the module is only loaded the first time the user attempts to extract
a function or a class with the dollar extractor.
<<eval=FALSE>>=
yada <- Module( "yada" )
.onLoad <- function(libname, pkgname) {
# placeholder
}
@
<<echo=FALSE,eval=TRUE>>=
options( prompt = "> ", continue = "+ " )
@
\subsection{Support for modules in skeleton generator}
The \code{Rcpp.package.skeleton} function has been improved to help
\pkg{Rcpp} modules. When the \texttt{module} argument is set to \texttt{TRUE},
the skeleton generator installs code that uses a simple module.
<<eval=FALSE>>=
Rcpp.package.skeleton( "testmod", module = TRUE )
@
Creating a new package using \textsl{Rcpp modules} is easiest via the call to
\code{Rcpp.package.skeleton()} with argument \code{module=TRUE} as a working
package with three example Modules results.
\subsection{Module documentation}
\pkg{Rcpp} defines a \code{prompt} method for the
\code{Module} class, allowing generation of a skeleton of an Rd
file containing some information about the module.
<<eval=FALSE>>=
yada <- Module( "yada" )
prompt( yada, "yada-module.Rd" )
@
We strongly recommend using a package when working with Modules. But in case a
manually compiled shared library has to loaded, the return argument of the
\texttt{getDynLib()} function can be supplied as the \texttt{PACKAGE} argument to
the \texttt{Module()} function as well.
\section{Future extensions}
\label{sec:future}
\texttt{Boost.Python} has many more features that we would like to port
to Rcpp modules : class inheritance, default arguments, enum
types, ...
\section{Known shortcomings}
\label{sec:misfeatures}
There are some things \textsl{Rcpp modules} is not good at:
\begin{itemize}
\item serialization and deserialization of objects: modules are
implemented via an external pointer using a memory location, which is
non-constant and varies between session. Objects have to be re-created,
which is different from the (de-)serialization that R offers. So these
objects cannot be save from session to session.
\item mulitple inheritance: currently, only simple class structures are
representable via \textsl{Rcpp modules}.
\end{itemize}
\section{Summary}
This note introduced \textsl{Rcpp modules} and illustrated how to expose
\proglang{C++} function and classes more easily to \proglang{R}.
We hope that \proglang{R} and \proglang{C++} programmers
find \textsl{Rcpp modules} useful.
\bibliographystyle{plainnat}
\bibliography{Rcpp}
\end{document}
|