From r.d.morey at rug.nl  Wed May 27 09:55:13 2009
From: r.d.morey at rug.nl (Richard Morey)
Date: Wed, 27 May 2009 09:55:13 +0200
Subject: [Rd] passing "..." arguments to a function called by eval()
In-Reply-To: <4A1C83FA.9010204@stats.uwo.ca>
References: <4A1C5B85.7040208@rug.nl> <4A1C83FA.9010204@stats.uwo.ca>
Message-ID: <4A1CF1E1.8080207@rug.nl>

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:
> 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
>



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