renjin icon indicating copy to clipboard operation
renjin copied to clipboard

R_tryEval implementation

Open david-bouyssie opened this issue 4 years ago • 3 comments

R_tryEval is currently not supported: https://github.com/bedatadriven/renjin/blob/master/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/Rinternals.java#L2256

Can we hope any workaround in the future?

david-bouyssie avatar Nov 16 '20 15:11 david-bouyssie

Pull requests welcome!

The implementation should be fairly simple, but I'm not sure what is expected in the event of error. See the implementation fo Rf_eval: https://github.com/bedatadriven/renjin/blob/cac412d232ad66d4ee8e37cfc8cb70a45e676e19/tools/gnur-runtime/src/main/java/org/renjin/gnur/api/Rinternals.java#L1796

akbertram avatar Nov 16 '20 15:11 akbertram

If fear I'm not enough skilled to submit a PR on this topic, sorry. I reported this issue because I have seen packages complaining for this missing function.

david-bouyssie avatar Nov 16 '20 16:11 david-bouyssie

The documentation for how this should behave is a bit sparse but the following snippet from the embedded guide says the following:

Handling Errors An application that embeds R must be careful to take care of handling errors that occur within the R engine appropriately. In the stand-alone version of R, an error will (after other on.error() activities in each evaluation frame) return control to the main input-eval-print loop. In general, this is not what is desired within another application. Instead, we want to trap such R errors and handle them from where the application passed control to the R engine. This can be done most readily using the C routine R_tryEval to evaluate the S expression. This does exactly what we want by guaranteeing to return to this point in the calling code whether an error occurred or not in evaluating the expression. This routine is similar to eval, taking both the expression to evaluate and an environment in which to perform the evaluation. It takes a third argument which is the address of an integer. If this is non-NULL, when the call returns, this contains a flag indicating whether there was an error or not.

Example

int
callFoo()
{
 SEXP e, val;
 int errorOccurred;
 int result = -1;

 PROTECT(e = allocVector(LANGSXP, 1));
 SETCAR(e, Rf_install("foo"));

 val = R_tryEval(e, R_GlobalEnv, &errorOccurred);

 if(!errorOccurred) {
   PROTECT(val);
   result = INTEGER(val)[0];
   UNPROTECT(1);
 } else {
   fprintf(stderr, "An error occurred when calling foo\n");
   fflush(stderr);
 }

    /* Assume we have an INTSXP here. */

 UNPROTECT(1); /* e */

return(result);
}

Note that this will, by default, take care of handling all types of errors that R would usually handle including signals. So if the user sends an interrupt to a computation (e.g. using Ctrl-C) while an R expression is being evaluated, R_tryEval will return and report an error. If the host application however changes the signal mask and/or handlers from R's own ones, of course this will not necessarily happen. In other words, the host application can control the signal handling differently

perNyfelt avatar Feb 08 '22 09:02 perNyfelt