[Rcpp-devel] handling ellipsis (...) in attributes exposed functions

Romain Francois romain at r-enthusiasts.com
Tue Oct 1 14:42:32 CEST 2013


Hello,

Behind the title, there is a simple idea. The ability to call a c++ 
function with variable number of arguments from R.

e.g we have a function "foo" defined in C++ and we want to call

foo( x, y, z )

I'd like to have the ability to define the function like this:

// [[Rcpp::export]]
void foo( Dots dots ){
     // do whatever
}

and generating whatever code is necessary so that the contents of the 
... is passed down ithout being evaluated (because sometimes it matters).

Dots would be a class that captures the arguments in a List and an 
Environment where the arguments can be evaluated.

This is (partially) implemented in Rcpp11. It mostly happened in this 
commit: 
https://github.com/romainfrancois/Rcpp11/commit/813e9029be02ed6d33e1ed775253382b3b80a339

The version I've implemented handles the "data" argument specifically, 
doing what you would expect. So I can do this:

#include <Rcpp.h>
using namespace Rcpp ;

// [[Rcpp::export]]
List foo( Dots dots ){
     return List::create(
         dots.size(),
         dots.eval(0)
         );
}

/*** R

     local({
         x <- y <- z <- rnorm(10)
         foo( x, y, z )
     })
     foo( Sepal.Length, data = iris )

*/

There are use cases for something like this. My latest example is order_ 
from dplyrRcpp to support something like this:

order_( Sepal.Length, Sepal.Width, data = iris )

It is now implemented like this:

order_ <- function(..., data){
     dots <- as.list( sys.call()[-1L] )
     parent_frame <- parent.frame()
     if( "data" %in% names(dots) ){
         dots <- dots[ names(dots) != "data" ]
         env <- as.environment(data)
         parent.env(env) <- parent_frame
     } else {
         env <- parent_frame
     }
     order_impl( dots, env )
}

and its c++:

// [[Rcpp::export]]
IntegerVector order_impl( List args, Environment env ){
     int nargs = args.size() ;
     SEXP tmp ;
     List variables(nargs) ;
     LogicalVector ascending(nargs) ;
     for(int i=0; i<nargs; i++){
         tmp = args[i] ;
         if( TYPEOF(tmp) == LANGSXP && CAR(tmp) == Rf_install("desc") ){
             variables[i] = Rf_eval( CAR(CDR(tmp) ), env ) ;
             ascending[i] = false ;
         } else{
             variables[i] = Rf_eval( tmp, env );
             ascending[i] = true ;
         }
     }
	OrderVisitors o(variables,ascending, nargs) ;
	return o.apply() ;
}

Anyway. I just wanted to start a discussion about this. Would people 
find it useful ...

Romain

-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30



More information about the Rcpp-devel mailing list