Le 29/05/10 09:10, Romain Francois a écrit :

Hello,

Currently, when exposing a c++ class to R through a Rcpp module, e.g:

class World {
public:
World() : msg("hello"){}
void set(std::string msg) { this->msg = msg; }
std::string greet() { return msg; }

private:
std::string msg;
};

void clearWorld( World* w){
w->set( "" ) ;
}

RCPP_MODULE(yada){
using namespace Rcpp ;

class_<World>( "World" )
.method( "greet", &World::greet )
.method( "set", &World::set )
.method( "clear", &clearWorld )
;
}



On the R side, we do :

# grab the module and the class
yada <- Module( "yada" )
World <- yada$World

# create an instance and play with it
w <- new( World )
w$greet()


The "w" object is of class "C++Object":

 > class( w )
[1] "C++Object"
attr(,"package")
[1] "Rcpp"

 > str( w )
Formal class 'C++Object' [package "Rcpp"] with 3 slots
..@ module :<externalptr>
..@ cppclass:<externalptr>
..@ pointer :<externalptr>

The "C++Object" class contains all the information that is needed
internally to dispatch to the internal method : pointer to its module,
pointer to its class wrapper and pointer to the actual object.



However, I think one of the next step would be for the user to define S4
methods for C++ classes, i.e it would be nice to be able to do something
like:

setMethod( "show", "World", function( object ){
writeLines( object$greet() )
} )

but right now we cannot because there is no S4 class "World", all c++
objects share the R class "C++Object".

This is the context of this question. I need help for this.

Options I am thinking about:

1) when the module is loaded, we define a "World" class that extends
"C++Object", i.e :

setClass( "World", contains = "C++Object" )

this would probably be the most natural way for the user. I am not sure
where to store that class. should I create a new environment for the
module, ...


2) make the dispatch internal, something like:

setInternalMethod( "show", World, function(object){
writeLines( object$greet() )
} )

so that :
- it registers an S4 "show" method for the "C++Object" class
- we maintain internally some sort of lookup table to find the show
method for the internal class.




We have the same problem in rJava where all java references have the
class "jobjRef", which makes it hard to do R side dispatch based on the
java class. I've used something like option 2 with rJava and the RImageJ
package once but I think option 1 is better and more natural.

It is probably more difficult to achieve option 1 with rJava because
since java has reflection, we get all classes for free, where we need to
specifically declare which ones with expose with Rcpp modules.
>
Anyway, I'm not asking for help in the C++ side, I realize this is
crazy. But some R-level help would be welcome.

Romain


Hi,

Few cup of coffee later, I have implemented option 1) :


######################################################################
require( Rcpp )
require( inline )

code <- ''

inc  <- '
class World {
public:
    World() : msg("hello"){}
    void set(std::string msg) { this->msg = msg; }
    std::string greet() { return msg; }

private:
    std::string msg;
};

void clearWorld( World* w){
        w->set( "" ) ;
}

RCPP_MODULE(yada){
        using namespace Rcpp ;
        
        class_<World>( "World" )
                .method( "greet", &World::greet )
                .method( "set", &World::set )
                .method( "clear", &clearWorld )
        ;

}

'
fx <- cxxfunction( signature(), "", include = inc, plugin = "Rcpp" )

yada <- Rcpp:::Module( "yada", getDynLib( fx ) )


# grab the World class
World <- yada$World

# create a new World object
w <- new( World )

setMethod( "show", "World", function(object){
        msg <- object$greet()
        writeLines( paste( "message from World:", msg )  )
} )

######################################################################



> w
message from World: hello




When the module is loaded (with the Module function), it registers the classes as simple extensions of the S4 class "C++Object" :

> str( getClass( "C++Object" ) )
Formal class 'classRepresentation' [package "methods"] with 11 slots
  ..@ slots     :List of 3
  .. ..$ module  : atomic [1:1] externalptr
  .. .. ..- attr(*, "package")= chr "methods"
  .. ..$ cppclass: atomic [1:1] externalptr
  .. .. ..- attr(*, "package")= chr "methods"
  .. ..$ pointer : atomic [1:1] externalptr
  .. .. ..- attr(*, "package")= chr "methods"
  ..@ contains  : list()
  ..@ virtual   : logi FALSE
  ..@ prototype :Formal class 'S4' [package ""] with 0 slots
 list()
  ..@ validity  : NULL
  ..@ access    : list()
  ..@ className : atomic [1:1] C++Object
  .. ..- attr(*, "package")= chr "Rcpp"
  ..@ package   : chr "Rcpp"
  ..@ subclasses:List of 1
.. ..$ World:Formal class 'SClassExtension' [package "methods"] with 10 slots
  .. .. .. ..@ subClass  : chr "World"
  .. .. .. ..@ superClass: chr "C++Object"
  .. .. .. ..@ package   : chr ".GlobalEnv"
  .. .. .. ..@ coerce    :function (from, strict = TRUE)
  .. .. .. ..@ test      :function (object)
  .. .. .. ..@ replace   :function (from, to, value)
  .. .. .. ..@ simple    : logi TRUE
  .. .. .. ..@ by        : chr(0)
  .. .. .. ..@ dataPart  : logi FALSE
  .. .. .. ..@ distance  : num 1
  ..@ versionKey:<externalptr>
  ..@ sealed    : logi FALSE


This way we can have both:
- internal dispatch of the traditional OO form : object$method( ... )
- S4 dispatch : generic( object, ... )


My next move is probably going to be melting both, so that we can define classic methods such as show internally, something like:

class_<World>( "World" )
                .method( "greet", &World::greet )
                .method( "set", &World::set )
                .method( "clear", &clearWorld )

                .S4_method( "show", &showWorld )
        ;

Romain


--
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://bit.ly/9CQ66r : RMetrics 2010
|- http://bit.ly/cork4b : highlight 0.1-8
`- http://bit.ly/bklUXt : RcppArmadillo 0.2.1

_______________________________________________
Rcpp-devel mailing list
[email protected]
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

Reply via email to