Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception handling and stack unwinding in R

In order to set up a coherent exception handling interface for my colleagues' and my R scripts, I would like to employ the following tryCatch structure.

  1. An outer tryCatch is wrapped around a given R script. It is used to catch and handle fatal errors that require the script to abort.
  2. User-specific tryCatch commands within the user's scripts. These should catch and, possibly, handle
    • 2a. non-fatal errors, where no script abortion is necessary
    • 2b. fatal-errors that require the script to abort. The error is handled by the outer tryCatch [see 1.]
    • 2c. fatal-errors with additional error information. Error handled by outer tryCatch.

The following code is how I would implement these features. However, since I am not an expert in R, I would like to ask whether this is a good approach. Specifically:

Q1. Is it ok not to specify an error handler in the inner tryCatch and to wait for the outer tryCatch to handle that error (see 2b. above and code below)?

Q2. Is rethrowing the same error (see 2c. above/below) within a handler correct/considered good coding style?

Thank you!

#outer tryCatch, see 1.
tryCatch({
  #user code block
  #2a. user specific tryCatch, object "vec" not defined
  tryCatch(print(vec),error=function(e) {print("Non-fatal error. Script execution continued.");print(e);})

  #2b. user specific tryCatch
  tryCatch(vec*2)

  #2c. user specific tryCatch
  tryCatch(vec*parameter1, error=function(e) {print("Additional fatal error information. Script execution aborted.");stop(e);})
  #end of user code block
},
     #outer tryCatch error handler in order to handle fatal errors
     error=function(e) {print("Fatal error");print(e);} 
    )
like image 779
cryo111 Avatar asked Oct 01 '12 11:10

cryo111


Video Answer


1 Answers

It's perfectly fine to catch only some errors, leaving other for the outer handler or no handler at all. The error system is quite a bit more flexible than typically used, so for re-throwing an error you might think of creating your own error type

ourError <-
    function(original, message, class="ourError")
{
    msg <- paste(message, conditionMessage(original), sep="\n  ")
    structure(list(message = msg, call = conditionCall(original)),
              class = c(class, class(original)))
}

and throwing and / or handling that

tryCatch(vec*parameter1, error=function(e) {
    err <- ourError(e, "addition fatal info; script aborted")
    stop(err)
})

One advantage of this is that additional behaviors can be specified in the top-level handler, using the class returned by ourError()

tryCatch({
    tryCatch(stop("oops"), error=function(e) {
        err <- ourError(e, "addition fatal info; script aborted",
                      c("fatal", "ourError"))
        stop(err)
    })
}, ourError=function(err) {
    message("We caught but didn't handle this:\n", err)
}, error =function(err) {
    message("This one got away: ", err)
})
like image 142
Martin Morgan Avatar answered Oct 03 '22 07:10

Martin Morgan