The condition system provides a paired set of tools that allow the author of a function to indicate that something unusual is happening, and the user of that function to deal with it. The function author signals conditions with functions like
stop() (for errors),
warning() (for warnings), and
message() (for messages), then the function user can handle them with functions like
withCallingHandlers(). Understanding the condition system is important because you’ll often need to play both roles: signalling conditions from the functions you create, and handle conditions signalled by the functions you call.
R offers a very powerful condition system based on ideas from Common Lisp. Like R’s approach to object-oriented programming, it is rather different to currently popular programming languages so it is easy to misunderstand, and there has been relatively little written about how to use it effectively. Historically, this has meant that few people (myself included) have taken full advantage of its power. The goal of this chapter is to remedy that situation. Here you will learn about the big ideas of R’s condition system, as well as learning a bunch of practical tools that will make your code stronger.
I found two resources particularly useful when writing this chapter. You may also want to read them if you want to learn more about the inspirations and motivations for the system:
A prototype of a condition system for R by Robert Gentleman and Luke Tierney. This describes an early version of R’s condition system. While the implementation has changed somewhat since this document was written, it provides a good overview of how the pieces fit together, and some motivation for its design.
Beyond exception handling: conditions and restarts by Peter Seibel. This describes exception handling in Lisp, which happens to be very similar to R’s approach. It provides useful motivation and more sophisticated examples. I have provided an R translation of the chapter at http://adv-r.had.co.nz/beyond-exception-handling.html.
I also found it helpful to work through the underlying C code that implements these ideas. If you’re interested in understanding how it all works, you might find my notes to be useful.
Want to skip this chapter? Go for it, if you can answer the questions below. Find the answers at the end of the chapter in Section 8.7.
What are the three most important types of condition?
What function do you use to ignore errors in block of code?
What’s the main difference between
Why might you want to create a custom error object?
Section 8.2 introduces the basic tools for signalling conditions, and discusses when it is appropriate to use each type.
Section 8.3 teaches you about the simplest tools for handling conditions: functions like
supressMessages()that swallow conditions and prevent them from getting to the top level.
Section 8.4 introduces the condition object, and the two fundamental tools of condition handling:
tryCatch()for error conditions, and
withCallingHandlers()for everything else.
Section 8.5 shows you how to extend the built-in condition objects to store useful data that condition handlers can use to make more informed decisions.
Section 8.6 closes out the chapter with a grab bag of practical applications based on the low-level tools found in earlier sections.
As well as base R functions, this chapter uses condition signalling and handling functions from rlang.