I've recently offered an extra set of hands to Dirk to work on the Rcpp package, this serves a good excuse to learn more about C++
Exception management was quite high on my list. C++ has nice exception handling (well not as nice as java, but nicer than C).
With previous versions of Rcpp, the idiom was to wrap up everything in a try/catch block and within the catch block, call the Rf_error
function to send an R error, equivalent of calling stop. Now things have changed and, believe it or not, you can now catch a C++ exception at the R level, using the standard tryCatch mechanism
throw
a C++ exception (inheriting from the class std::exception
) at the C++ level, and the exception is not picked up by the C++ code, it automatically sends an R condition that contain the message of the exception (what the what member function of std::exception gives) as well as the class of the exception (including namespace)
This, combined with the new inline support for Rcpp, allows to run this code, (also available in the inst/examples/RcppInline directory of Rcpp)
require(Rcpp) require(inline) funx <- cfunction(signature(), ' throw std::range_error("boom") ; return R_NilValue ; ', Rcpp=TRUE, verbose=FALSE)
Here, we create the funx
"function" that compiles itself into a C++ function and gets dynamically linked into R (thanks to the inline package). The relevant thing (at least for this post) is the throw
statement. We throw a C++ exception of class "std::range_error" with the message "boom", and what follows shows how to catch it at the R level:
tryCatch( funx(), "C++Error" = function(e){ cat( sprintf( "C++ exception of class '%s' : %s\n", class(e)[1L], e$message ) ) } ) # or using a direct handler tryCatch( funx(), "std::range_error" = function(e){ cat( sprintf( "C++ exception of class '%s' : %s\n", class(e)[1L], e$message ) ) } )
... et voila
Under the carpet, the abi unmangling namespace is at work, and the function that grabs the uncaught exceptions is much inspired from the verbose terminate handler that comes with the GCC
Part of this was inspired from the new java exception handling that came with the version 0.8-0 of rJava, but cooked with C++ ingredients