Reputation: 32978
The stop
function in R can be called with a list object in order to signal an exception of a particular type. For example to signal a foo
exception, we can do:
foo <- list (
message = "my foo error"
)
class(foo) <- c("foo", "condition")
tryCatch (
stop(foo),
foo = function(e){"never mind foo."}
)
Is there an interface for doing this (signaling custom exceptions) from C code? The Rf_error
only allows for raising generic errors, it does not allow for specifying a exception class.
Upvotes: 1
Views: 246
Reputation: 32978
Based on the suggestions above I wrote this function that does what I need:
void signal_exception(const char* message, const char* condition){
//the condition object
SEXP vec = PROTECT(allocVector(VECSXP, 1));
SET_VECTOR_ELT(vec, 0, mkString(message));
setAttrib(vec, R_NamesSymbol, mkString("message"));
//the class vector
SEXP cls = PROTECT(allocVector(STRSXP, 3));
SET_STRING_ELT(cls, 0, mkChar(condition));
SET_STRING_ELT(cls, 1, mkChar("error"));
SET_STRING_ELT(cls, 2, mkChar("condition"));
setAttrib(vec, R_ClassSymbol, cls);
//signal the condition by calling base::stop
SEXP stop_sym = PROTECT(Rf_install("stop"));
SEXP call = PROTECT(Rf_lang2(stop_sym, vec));
UNPROTECT(4);
Rf_eval(call, R_GlobalEnv);
}
It basically generalizes Rf_error
with a second argument that you can use to specify the class of the error.
I don't think it is very elegant to call base::stop
from C, only to have it call back to .Internal(.signalCondition())
but I it looks like there is currently no API for signalling the condition directly from C.
Upvotes: 4
Reputation: 368191
A standard example of how to do it in C++ is in this Rcpp Gallery post.
Taking just the first part with one minor edit:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double takeLog(double val) {
try {
if (val <= 0.0) { // log() not defined here
throw std::range_error("Inadmissible value");
}
return log(val);
} catch(std::exception &ex) {
forward_exception_to_r(ex);
} catch(...) {
stop("c++ exception (unknown reason)");
}
return NA_REAL; // not reached
}
works as expected:
R> sourceCpp("/tmp/ex.cpp")
R> takeLog(-1)
Error: Inadmissible value
R>
The remainder of that post has some details.
Upvotes: 2