[Rcpp-devel] Exposing constructors

Romain Francois romain at r-enthusiasts.com
Fri Nov 5 14:33:04 CET 2010


Hi,

As a follow up on yesterday's email. I've added some more code that 
allows multiple constructors to e registered with a simple mechanism for 
deciding which one is to be used.

The interface has changed, the second template parameter has disapeared 
and constructors are now registered through .constructor.

One important thing is that (for now at least), the default constructor 
is no more automatically registered, so one has to manually register it 
using .default_constructor.

The following code shows an example (with the typo from yesterday fixed 
as well ;-) )



require( Rcpp )
require( inline )
inc <- '

class Randomizer {
public:

     Randomizer() : min(0), max(1){}
     Randomizer( double min_, double max_) : min(min_), max(max_){}

	NumericVector get( int n ){
		RNGScope scope ;
		return runif( n, min, max );
	}

private:
	double min, max ;
} ;

RCPP_MODULE(mod){

	class_<Randomizer>( "Randomizer" )

	    .default_constructor()
	    .constructor( init_2<double,double>() )
	
		.method( "get" , &Randomizer::get ) ;

}
'

fx <- cxxfunction( , '', includes = inc, plugin = "Rcpp" )
mod <- Module( "mod", getDynLib( fx ) )
Randomizer <- mod$Randomizer
r <- new( Randomizer, 10.0, 20.0 ) ;
r$get(10)
r$get(5)

r <- new( Randomizer ) ;
r$get(10)
r$get(5)



So Randomizer has two constructors.
The default one is registered by default_constructor
The one that takes two double is registered by this line :

.constructor( init_2<double,double>() )




So how does this work. Internally I maintain a vector of constructors, 
and I invoke the first one that is "valid" for the supplied list of 
arguments.

What does "valid" mean is up to the developer, with a sensible default.

In addition to the signature definition ( init_2<double,double> ), one 
can also pass a function to .constructor as the second argument. This 
function must have the same signature as this one:

bool yes( SEXP* args, int nargs){
     return true ;
}

The default constructor is judged valid if no arguments are passed down, 
and a constructor taking 2 arguments is judged valid if two arguments 
are passed down, as generated by this function template:


template<int n>
bool yes_arity( SEXP* args, int nargs){
     return nargs == n ;
}

that is used in the default arguments of .constructor

     template <typename U0, typename U1>
     self& constructor( init_2<U0,U1>, ValidConstructor valid = 
&yes_arity<2> )


Those are sensible defaults because most of the time people want to 
expose several constructors to deal with different arity.

But, the programmer can supply his own function, so for example if a 
constructor is only valid for a character vector of length two, one 
could pass this function to .constructor:


bool test( SEXP* args, int nargs ){
	if( nargs != 1 ) return false ;
	if( TYPEOF( args[0] ) != STRSXP ) return false ;
	if( LENGTH( args[0] ) != 2 ) return false ;
	return true ;
}

And do something like :

.constructor( init_1<CharacterVector>(), &test )

This might change again until Rcpp 0.8.9 is released. Suggestions are 
welcome. I might change "init_%d" to "signature_%d".

Romain

Le 04/11/10 11:29, Romain Francois a écrit :
> Hello,
>
> This question has come up a few times now. How can I use another
> constructor than the default constructor in a class exposed by Rcpp
> modules.
>
> I've made a few changes to Rcpp to allow that. The new restriction is
> that :
> - we can only expose one constructor (we need to think about various
> ways to implement dispatch)
> - the constructor needs to have 0, 1 or 2 arguments. We will handle more
> later, but I wanted people to test this first before launching a massive
> copy/paste adventure. Also, the pattern is simple enough so that other
> people can do it instead of me. (I can explain it a bit more if people
> volunteer).
>
> As an illustration, consider this simple class :
>
> class Randomizer {
> public:
> Randomizer( double min_, double max_) : min(min), max(max_){}
>
> NumericVector get( int n ){
> RNGScope scope ;
> return runif( n, min, max );
> }
>
> private:
> double min, max ;
> } ;
>
> I can explain what it does, but I feel this is self explanatory.
>
> What is relevant here is the constructor. There is no default
> constructor (although the compiler might generate one on our behalf),
> and we want to use the constructor that takes two doubles.
>
> This is how we would do it (the syntax might change before Rcpp 0.8.9 is
> out):
>
> RCPP_MODULE(mod){
>
> class_< Randomizer, init_2<double,double> >( "Randomizer" )
> .method( "get" , &Randomizer::get ) ;
>
> }
>
> The relevant bit here is the second template argument of class_.
>
> Full example below:
>
>
> require( Rcpp )
> require( inline )
> inc <- '
>
> class Randomizer {
> public:
> Randomizer( double min_, double max_) : min(min), max(max_){}
>
> NumericVector get( int n ){
> RNGScope scope ;
> return runif( n, min, max );
> }
>
> private:
> double min, max ;
> } ;
>
> RCPP_MODULE(mod){
>
> class_< Randomizer, init_2<double,double> >( "Randomizer" )
>
> .method( "get" , &Randomizer::get ) ;
>
> }
> '
>
> fx <- cxxfunction( , '', includes = inc, plugin = "Rcpp" )
> mod <- Module( "mod", getDynLib( fx ) )
> Randomizer <- mod$Randomizer
> r <- new( Randomizer, 10.0, 20.0 ) ;
> r$get(10)
> r$get(5)
>
>
> Have fun !
>
> Romain
>
>


-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://bit.ly/czHPM7 : Rcpp Google tech talk on youtube
|- http://bit.ly/9P0eF9 : Google slides
`- http://bit.ly/cVPjPe : Chicago R Meetup slides




More information about the Rcpp-devel mailing list