From r.d.morey at rug.nl  Tue May 26 23:13:41 2009
From: r.d.morey at rug.nl (Richard Morey)
Date: Tue, 26 May 2009 23:13:41 +0200
Subject: [Rd] passing "..." arguments to a function called by eval()
Message-ID: <4A1C5B85.7040208@rug.nl>

Hi everyone,

I am starting learn to call C code from within R. So far, I've been 
trying toy problems to see if I can get them to work. One of the things 
I'd like to do is pass an arbitrary R function to C, evaluate the value 
in the C code using eval, and then return it. I also want to allow an 
arbitrary number of arguments to the function using "...".

The code for my toy package looks like this:
########## R code, in pkg/R directory
dTest <-
function(x,...){
    retVal    = .Call("dTestC",x[1],dnorm,...,rho=new.env(),PACKAGE="pkg")
    return(retVal)
}

########## C code, in pkg/src directory

SEXP dTestC(SEXP dblX, SEXP funFn, SEXP dots, SEXP rho);

/*--------------------------*/


SEXP dTestC(SEXP dblX, SEXP funFn, SEXP dots, SEXP rho){

  SEXP retVal;
  SEXP R_fcall;

  PROTECT(retVal = NEW_NUMERIC(1));
  PROTECT(R_fcall = lang3(funFn, R_NilValue, R_NilValue));
  SETCADR(R_fcall, dblX);
  SETCADDR(R_fcall, dots);
  retVal = eval(R_fcall, rho);
  UNPROTECT(2);

  return(retVal);

}

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

When I call the dTest() function, the first required argument and the 
first optional argument are both used, but not the ones after that.

I'm modeling this after what I found in the 'HI' package. I don't 
understand a few few things. First, the C code used by the arms() 
function in the HI package somehow manages to evaluate an R function, 
with "..." arguments, without passing the SEXP dots argument. I haven't 
been able to figure out how, looking at the source.

Second, in the Rinternal documents it mentions that  "..." is one 
argument.  So, I figured I could get away with doing what I've done 
above, and the SETCADDR function would set all the arguments in "..." in 
one go. This is evidently wrong.

How can I do what I want to do? I know the HI package does it, but I 
don't know how. I might pass all the arguments as members of one list, 
but that seems like a waste. What am I doing/thinking wrong here? What's 
the best way to do what I want to do?

Thanks for your help,

Richard



[Rd] passing "..." arguments to a function called by eval()
Richard Morey