Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate an R warning safely in Rcpp

Tags:

We know that calling Rf_error() should be avoided in Rcpp as it involves a longjmp over C++ destructors on the stack. This is why we rather throw C++ exceptions in Rcpp code (like throw Rcpp::exception("...") or via the stop("...") function).

However, R warnings may also result in a call to Rf_error() (this behavior depends on the warn option). So, a call to Rf_warning() is also risky.

Rcpp::sourceCpp(code = '

   #include <Rcpp.h>
   using namespace Rcpp;

   class Test {
      public:
         Test() { Rcout << "start\\n"; }
         ~Test() { Rcout << "end\\n"; }
   };

   // [[Rcpp::export]]
   void test() {
      Test t;
      Rf_warning("test");
   }
')

options(warn=10)
test()
## start
## Error in test() : (converted from warning) test

We see that the destructor hasn't been called (there's no "end" message).

How to generate an R warning in a C++-destructor-friendly way?

like image 993
gagolews Avatar asked Jul 03 '14 15:07

gagolews


Video Answer


2 Answers

One of the solutions I came up with involves calling the R's warning function from Rcpp:

// [[Rcpp::export]]
void test() {
   Test t;
   Function warning("warning");
   warning("test"); // here R errors are caught and transformed to C++ exceptions
}

which gives the correct behavior if warn>2:

start
end
Error in eval(expr, envir, enclos) : (converted from warning) test

I wonder if anybody has a better idea for that.

like image 161
gagolews Avatar answered Sep 27 '22 19:09

gagolews


I would recommend using stop() (which is a wrapper around try/catch) instead:

With your code slightly modified:

#include <Rcpp.h>
using namespace Rcpp;

class Test {
public:
    Test() { Rcout << "start\n"; }
    ~Test() { Rcout << "end\n"; }
};

// [[Rcpp::export]]
void test() {
    Test t;
    Rf_warning("test");
}

// [[Rcpp::export]]
void test2() {
    Test t;
    stop("test2");
}

/*** R
options(warn=10)
#test()
test2()
*/

I get the desired behaviour:

R> sourceCpp("/tmp/throw.cpp")

R> options(warn=10)

R> #test()
R> test2()
start
end
Error in eval(expr, envir, enclos) (from srcConn#3) : test2
R> 

The longjmp issue is known, but you do not win by avoiding the mechanisms we have to unwind objects.

like image 34
Dirk Eddelbuettel Avatar answered Sep 27 '22 20:09

Dirk Eddelbuettel