Richard Morey
2009-May-26 21:13 UTC
[Rd] passing "..." arguments to a function called by eval()
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
Duncan Murdoch
2009-May-27 00:06 UTC
[Rd] passing "..." arguments to a function called by eval()
On 26/05/2009 5:13 PM, Richard Morey wrote:> 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);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> > /*--------------------------*/ > > > 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 > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel