From lgautier at gmail.com  Thu Jan 14 14:27:33 2010
From: lgautier at gmail.com (Laurent Gautier)
Date: Thu, 14 Jan 2010 14:27:33 +0100
Subject: [Rd] how to call a function from C
In-Reply-To: <4B4F0B1D.8060108@dbmail.com>
References: <mailman.31.1263466812.18774.r-devel@r-project.org>
	<4B4F031F.7000202@gmail.com> <4B4F0B1D.8060108@dbmail.com>
Message-ID: <4B4F1BC5.8020307@gmail.com>

On 1/14/10 1:16 PM, Romain Francois wrote:
> On 01/14/2010 12:42 PM, Laurent Gautier wrote:
>>> Hi,
>>>
>>> In Rcpp, we now have a "Function" class to encapsulate functions
>>> (they cover all three kinds, but this may change).
>>
>> Just a note on that: there is probably no hurry to do so.
>> rpy2 is also having CLOSXP, BUILTINSXP, and SPECIALSXP represented as
>> one function-like class and seems to be behave reasonably while a lot of
>> other things seem more urgent to sort out.
>>
>>> To call the function, what we do is generate a call with the function
>>> as the first node and then evaluate the call.
>>>
>>> SEXP stats = PROTECT( R_FindNamespace( mkString( "stats") ) ); SEXP
>>> rnorm = PROTECT( findVarInFrame( stats, install( "rnorm") ) ) ; SEXP
>>> call = PROTECT( LCONS( rnorm, CONS( ScalarInteger(10),
>>> CONS(ScalarReal(0), R_NilValue ) ) ) ); SEXP res = PROTECT( eval(
>>> call , R_GlobalEnv ) ); UNPROTECT(4) ; return res ;
>>>
>>> It works, but I was wondering if there was another way. I've seen
>>> applyClosure, but I'm not sure I should attempt to use it or if using
>>> a call like above is good enough.
>>
>> Using R_tryEval() will let you evaluate an expression in a given
>> environment, as well as capture an eventual error occurring during its
>> evaluation (and translate it as an exception).
>
> Sure. I did not want to over-complicate the question.
>
> I'm currently reviewing tryEval and its underlying R_TopLevelExec which
> does not give me enough : when the error occurs, it'd be useful that the
> function returns the condition object instead of NULL.

I possibly went the same path, and ended with R_tryEval. When looking at 
it, I could not figure out any way to get what I wanted outside using 
"geterrmessage" in base.
The error string is in the variable errbuf (in src/main/error.c), with 
no obvious route to access it (and if truly no route, this might be 
something missing from the R C-API).

>>> Romain
>>>
>>> PS: using Rcpp's C++ classes you would express the code above as :
>>>
>>> Environment stats("package:stats") ; Function rnorm = stats.get(
>>> "rnorm" ) return rnorm( 10, 0.0 ) ;
>>
>> Feel free to snoop in rpy2's rpy/rinterface/rinterface.c and look for
>> "do_try_eval". The behavior looks very similar, the above snippet in
>> rpy2 would write like:p/

I meant "do_eval_expr".


>> from rpy2.robjects.packages import importr
>> stats = importr('stats')
>> stats.rnorm(10, 0.0)
>
> nice
>



[Rd] how to call a function from C
Laurent Gautier