[Rd] Interfacing a C++ class

soeren.vogel at uzh.ch soeren.vogel at uzh.ch
Tue Jun 7 10:10:51 CEST 2011


On 06.06.2011, at 13:42, Romain Francois wrote:

> Le 04/06/11 16:31, soeren.vogel at uzh.ch a écrit :
> 
>> FOO is the C++ object, and Foo should be the S4 class. If the user creates an object, say bar, from class Foo, the creation process automatically makes a new FOO object relating to bar in that a unique name of the FOO instance is stored in a slot of bar. All the user then has to do is modify bar by simple assignments. The getters and setters ("$", "[") are set up and work. Each modification goes in hand with assigning new values to bar as well as updating the FOO object through available setters from FOO.
>> 
>> So far, this way has brought me to about 100 lines, but now I read about ReferenceClasses and was wondering, if there is a much easier way of achieving my goals. Moreover, I was not sure any longer if my goals make sense or if a more advanced programmer would do it totally different (and could share some structural thinking on their approach).
>> 
>> The idea behind my way of doing was based upon several considerations. First, a "classical" R object would not confuse users, as I assume users of my package to be rather non-skilled (and not willing to change that). Second, I want to create a properly programmed package for distribution on CRAN and publication, eventually. Third, I want to save objects across sessions. So if a user restores a session, a simple command, say, restore(), would do the trick to build all the related C++ objects again. However, I admit that I still have not figured out how to automatically clean up the workspace correctly before leaving a session, wanted or unwanted, that is, clean up memory before leaving home. Fourth, pure arithmetic check is done in C++, however, semantic check *should* be left to R, and the validity and class routines seem to be perfect for this. Fifth, some work should be done in R, such as the passing of data frames or samples from distributions.
> 
> Hello,
> 
> A C++ class that is exposed through an Rcpp module is already a reference class, and so you can add methods, etc ...
> 
> Consider this example :
> 
> require(inline)
> require(Rcpp)
> 
> fx <- cxxfunction( , '', includes = '
> 
> class FOO{
> public:
>    FOO( double x_, double y_): x(x_), y(y_){}
> 
>    double x ;
>    double y ;
> 
>    void move( double dx, double dy){
>        x += dx ;
>        y += dy ;
>    }
> } ;
> 
> RCPP_MODULE(mod){
> 
>    class_<FOO>("FOO" )
> 
>        .constructor<double,double>()
> 
>        .field( "x", &FOO::x )
>        .field( "y", &FOO::y )
> 
>        .method( "move", &FOO::move )
>        ;
> }
> 
> 
> ', plugin = "Rcpp" )
> mod <- Module( "mod", getDynLib(fx),mustStart = TRUE )
> 
> # grab the exposed C++ class
> FOO <- mod$FOO
> 
> # add R methods
> FOO$methods(
>    bla = function() x+y,
>    reset = function() {
>        x <<- 0.0
>        y <<- 0.0
>    }
> )
> # create an instance
> f <- new( FOO, 2.0, 3.0 )
> 
> # call an R method
> f$reset()
> 
> # call a C++ method
> f$move( 2.0, 2.0 )
> 
> # call an R method
> f$bla()

Thanks Simon and Romain for your great help! That C++ classes exposed via Rcpp-modules are already reference classes helps a lot and saves time for unnecessary mirroring. According to Romain saving class objects across sessions remains to be implemented in Rcpp. I have not browsed the rJava package extensively, but I found serialize() (base) and this function seems to provide a workaround. Yet, I do not know how to use it in practice with my package. Some thoughts: consider the small FOO example below. Then, on accidental crash or quit(save="yes"), or whatever users may do, R "should" know that it has to serialise all existing FOO objects. Note, that in my package these objects are "sort of lists" that can become quite large (say, a vector of 15,000 numeric values plus a character string). After restoring a previously saved image, R "should know" to load my package, and that in turn should deserialise every FOO object present in the image. Sounds like a not too complicated task, something like .dofirst()/.dolast() -- but that again exceeds my R and C++ programming skills, and I hope that you experts may share an idea. Thanks, Sören



More information about the R-devel mailing list