Search code examples
c++rerror-handlingrcpp

How to make a cpp (Rcpp) function that triggers "useful" error messages if the input types are wrong?


Consider this cpp function

// [[Rcpp::export]]
int timesTwo(int x) {
  return x * 2;
}

If I input an object of wrong type in this function (e.g. "character"), apparently, it will not work and show this error message Error: Not compatible with requested type: [type=character; target=integer].

However, I want to make it a bit more informative, for example

Error in timesTwo(int x)
Error: Not compatible with requested type: [type=character; target=integer].

or

Error in the parameter x of timesTwo(int x)
Error: Not compatible with requested type: [type=character; target=integer].

I want to know how I can do it in cpp?


Solution

  • There are two obvious ways to handle this. The first is that you invoke your cpp function via a wrapper in R that does your type checking in advance. For example:

    Rcpp::cppFunction('
      int times_two_cpp(int x) {
        return x * 2;
      }')
    
    timesTwo <- function(x) {
      if(!is.integer(x)) stop("'x' should be an integer, not ", typeof(x))
      times_two_cpp(x)
    }
    

    Testing, we have:

    timesTwo(5L)
    #> [1] 10
    
    timesTwo('hello')
    #> Error in timesTwo("hello") : 'x' should be an integer, not character
    

    The second option is to allow your C++ function to take any R object, and do the type-checking internally. This requires some knowledge of R internals

    Rcpp::cppFunction('
      Rcpp::IntegerVector timestwo(SEXP x) {
        if(TYPEOF(x) != INTSXP) {
         Rcpp::stop("in the parameter x of timesTwo - x is not an integer");
        }
        Rcpp::IntegerVector result(x);
        return result * 2;
       }
    ')
    

    Resulting in

    timestwo(5L)
    #> [1] 10
    
    timestwo('hello')
    #> Error: in the parameter x of timesTwo - x is not an integer