From romain.francois at dbmail.com  Thu Jan 14 17:19:40 2010
From: romain.francois at dbmail.com (Romain Francois)
Date: Thu, 14 Jan 2010 17:19:40 +0100
Subject: [Rd] how to call a function from C
In-Reply-To: <4B4F1BC5.8020307@gmail.com>
References: <mailman.31.1263466812.18774.r-devel@r-project.org>
	<4B4F031F.7000202@gmail.com> <4B4F0B1D.8060108@dbmail.com>
	<4B4F1BC5.8020307@gmail.com>
Message-ID: <4B4F441C.9050705@dbmail.com>

On 01/14/2010 02:27 PM, Laurent Gautier wrote:
>
> 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).

It seems to be the regular way around this gap. Martin Morgan gave the 
same advice (using geterrmessage) here last week. it only gives you the 
error message though

I've been staring at R_ToplevelExec, begincontext and addCondHands. Some 
day, I'll understand how to connect the dots. Not today though.

Romain

>>>> 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".

thanks.

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


-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://tr.im/KfKn : Rcpp 0.7.2
|- http://tr.im/JOlc : External pointers with Rcpp
`- http://tr.im/JFqa : R Journal, Volume 1/2, December 2009



[Rd] how to call a function from C
Romain Francois