Exceptions

You may have noticed that R sometimes gives you an error when you enter an invalid expression. For example:

> 12 / "hat"
Error in 12/"hat" : non-numeric argument to binary operator

Other times, R may just give you a warning:

> if (c(TRUE,FALSE)) TRUE else FALSE
[1] TRUE
Warning message:
In if (c(TRUE, FALSE)) TRUE else FALSE :
  the condition has length > 1 and only the first element will be used

Like other modern programming languages, R includes the ability to signal exceptions when unusual events occur and catch to exceptions when they occur. If you are writing your own R programs, it is usually a good idea to stop execution when an error occurs and alert the user (or calling function). Likewise, it is usually a good idea to catch exceptions from functions that are called within your programs.

It might seem strange to talk about exception handling in the context of environments, but exception handling and environments are closely linked. When an exception occurs, the R interpreter may need to abandon the current function and signal the exception in the calling environment.

This section explains how the error-handling system in R works.

If something occurs in your code that requires you to stop execution, you can use the stop function. For example, suppose that you had written a function called dowork(filename) to automatically generate some charts and save them to a file specified by the argument filename. Suppose that R couldn’t write to the file, possibly because the directory didn’t exist. To stop execution and print a helpful error message, you could structure your code like this:

> doWork <- function(filename) {
+   if(file.exists(filename)) {
+     read.delim(filename)
+   } else {
+     stop("Could not open the file: ", filename)
+   }
+ }
> doWork("file that doesn't exist")
Error in doWork("file that doesn't exist") : 
  Could not open the file: file that doesn't exist

If something occurs in your code that you want to tell the user about, but which isn’t severe enough to normally stop execution, you can use the warning function. Reusing the example above, if the file “filename” already exists, then the function will simply return the string "la la la". If the file does not exist, then the function will warn the user that the file does not exist.

> doNoWork <- function(filename) {
+   if(file.exists(filename)) {
+     "la la la"
+   } else {
+     warning("File does not exist: ", filename)
+   }
+ }
> doNoWork("another file that doesn't exist")
Warning message:
In doNoWork("another file that doesn't exist") :
  File does not exist: another file that doesn't exist

If you just want to tell the user something, then you can use the message function:

> doNothing <- function(x) { 
+   message("This function does nothing.") 
+ }
> doNothing("another input value")
This function does nothing.

Suppose that you are writing a function in R called foo that calls another function called bar. Furthermore, suppose that bar sometimes generates an error, but you don’t want foo to stop if the error is generated. For example, maybe bar tries to open a file but signals an error when it can’t open the file. If bar can’t open the file, maybe you want foo to try doing something else instead.

A simple way to do this is to use the try function. This function hides some of the complexity of R’s exception handling. Here’s an example of how to use try:

> res <- try({x <- 1}, silent=TRUE)
> res
[1] 1
> res <- try({open("file that doesn't exist")}, silent=TRUE)
> res
[1] "Error in UseMethod(\"open\") : \n  no applicable method for 'open'
applied to an object of class \"character\"\n"
attr(,"class")
[1] "try-error"

The try function takes two arguments, expr and silent. The first argument, expr, is the R expression to be tried (often a function call). The second argument specifies whether the error message should be printed to the R console (or stderr); the default is to print errors. If the expression results in an error, then try returns an object of class "try-error".

A more capable function is tryCatch. The tryCatch function takes three sets of arguments: an expression to try, a set of handlers for different conditions, and a final expression to evaluate. For example, suppose that the following call was made to tryCatch:

tryCatch(expression, handler1, handler2, ..., finally=finalexpr)

The R interpreter would first evaluate expression. If a condition occurs (an error or warning), R will pick the appropriate handler for the condition (matching the class of the condition to the arguments for the handler). After the expression has been evaluated, finalexpr will be evaluated. (The handlers will not be active when this expression is evaluated.)