Skip to content

passing "..." arguments to a function called by eval()

3 messages · Duncan Murdoch, Richard Morey

#
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
#
On 26/05/2009 5:13 PM, Richard Morey wrote:
I wouldn't expect that to work, though it might if .Call is doing fancy 
things with the args.  The way I'd do it is to pass list(...) as a 
single argument to .Call, and within your C code, extract the elements. 
  It would make the call to funFn more complicated (it wants a pairlist 
of arguments, list(...) will be a vector list), but it looks safer than 
what you did.

There's an example in the Writing R Externals manual at the end of 
section 5.10.2 using ... with .External.  (It mentions using list(...) 
with .Call.)

Duncan Murdoch
#
I was still puzzled by the fact that HI managed to do it without using 
complicated lists, so recombed the HI source to see what I missed the 
first time.

HI defines a second function f=function(x) passedFun(x,...) and then 
passes that to the C code using .Call. I had missed something subtle, 
and was using

f=function(x,...) passedFun(x,...)

and passing that to .Call. That, of course, didn't work, leading me to 
try to find the solution below. It is critical that you don't have ... 
as an argument to the dummy function you define. That way, ... will be 
in scope in the dummy function and you don't have to pass it to .Call.

Richard
Duncan Murdoch wrote: