Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to catch error in C for Rf_eval R?

Tags:

c

r

try-catch

I need to catch an error in Rf_eval in C. Is that even possible?

Some sample function

SEXP foo(SEXP x, SEXP env) {
   SEXP res;
   PROTECT(res = Rf_eval(x, env));
   UNPROTECT(1); 
   return res;
}

I have tried Rcpp_eval from Rcpp and Rcpp11, but both of them don't work for my case, I need to call Rf_eval directly. Is it possible to catch an error directly in C? If so how?

like image 387
romants Avatar asked Dec 15 '14 14:12

romants


1 Answers

use R_tryEval or R_tryEvalSilent in Rinternals.h

#include <Rdefines.h>

SEXP foo(SEXP fun, SEXP env)
{
    int err = 0;
    R_tryEval(fun, env, &err);
    if (err)
        Rprintf("error occurred\n");
    return R_NilValue;
}

with

> .Call("foo", quote(stop("oops")), .GlobalEnv)
Error: oops
error occurred
NULL

Here's a little more complete example, retrieving the last error

#include <Rdefines.h>

SEXP silent(SEXP fun, SEXP env, SEXP errmsg)
{
    int err = 0;
    SEXP result = PROTECT(R_tryEvalSilent(fun, env, &err));
    if (err) {
        SEXP msg = PROTECT(R_tryEvalSilent(errmsg, env, &err));
        if (!err)
            Rprintf("error occurred: %s",
                    CHAR(STRING_ELT(msg, 0)));
        else
            Rprintf("(unknown) error occurred");
        UNPROTECT(1);
        result = R_NilValue;
    }

    UNPROTECT(1);
    return result;
}

used as

.Call("silent", quote(stop("oops")), .GlobalEnv, quote(geterrmessage()))

Probably it makes a lot of sense to leave as much code as possible (e.g., conditional error handling) at the R level, either by wrapping the function to be evaluated or providing a custom error handling function instead of geterrmessage().

like image 174
Martin Morgan Avatar answered Oct 20 '22 10:10

Martin Morgan