- Fail fast: if something’s wrong, you want to know immediately.
- Have confidence the code works as intended.

28 Oct. 2019
library(readr) log(-1)
## Warning in log(-1): NaNs produced
## [1] NaN
this_object_DNE
## Error in eval(expr, envir, enclos): object 'this_object_DNE' not found
readr::read_csv("inst/extdata/baxter.metadata.csv")
## Parsed with column specification: ## cols( ## sample = col_double(), ## fit_result = col_double(), ## Site = col_character(), ## Dx_Bin = col_character(), ## dx = col_character(), ## Hx_Prev = col_double(), ## Hx_of_Polyps = col_double(), ## Age = col_double(), ## Gender = col_character(), ## Smoke = col_double(), ## Diabetic = col_double(), ## Hx_Fam_CRC = col_double(), ## Height = col_double(), ## Weight = col_double(), ## NSAID = col_double(), ## Diabetes_Med = col_double(), ## stage = col_double() ## )
library(rlang) message("This is a benign message.")
## This is a benign message.
warning("Something could be wrong, but we can continue.")
## Warning: Something could be wrong, but we can continue.
abort("The program can't go on, burn it all down!")
## The program can't go on, burn it all down!
4th type of condition: Interrupt
: when you press “Stop” or ctrl-c
.
my_log <- function(x, base = exp(1)) { if (!is.numeric(x)) { abort(paste0( "`x` must be numeric; not ", typeof(x), "." )) } if (!is.numeric(base)) { abort(paste0( "`base` must be numeric; not ", typeof(base), "." )) } base::log(x, base = base) } my_log('abc')
## `x` must be numeric; not character.
tryCatch( error = function(cnd) { # do this if you catch an error code_to_run_when_error_is_thrown }, { # try this code_to_run_while_handlers_are_active } )
Why? When you want to modify the default behavior.
tryCatch doesn’t return to the try
after Catch
ing an error
tryCatch( error = function(cnd) { # catch an error message("Oh no, there's an error!") }, { # try this bad_thing_happened = TRUE if( bad_thing_happened) { abort("We've gotta kill the program") } message("This code is never run!") } )
## Oh no, there's an error!
# the code outside the tryCatch block continues on afterward
You can access the condition message in the Catch
tryCatch( error = function(cnd) { # catch an error message("Oh no, there's an error!") message(conditionMessage(cnd)) }, { # try this bad_thing_happened = TRUE if( bad_thing_happened) { abort("We've gotta kill the program") } message("This code is never run!") } )
## Oh no, there's an error!
## We've gotta kill the program
# the code outside the tryCatch block continues on afterward
withCallingHandlers( warning = function(cnd) { code_to_run_when_warning_is_signalled }, message = function(cnd) { code_to_run_when_message_is_signalled }, code_to_run_while_handlers_are_active )
withCallingHandlers returns to the try
after a Catch
withCallingHandlers( warning = function(cnd) { message("Caught a warning!") # do something special }, { warning("Something might be wrong.\n") message("But let's keep going anyway.") } )
## Caught a warning!
## Warning in withCallingHandlers(warning = function(cnd) {: Something might be wrong.
## But let's keep going anyway.
library(glue) # Write a function that wraps `abort` abort_bad_argument <- function(arg, must, not = NULL) { # create a custom message msg <- glue::glue("`{arg}` must {must}") # append to the message if `not` was specified if (!is.null(not)) { not <- typeof(not) msg <- glue::glue("{msg}; not {not}.") } # pass custom metadata to abort abort("error_bad_argument", message = msg, arg = arg, must = must, not = not ) }
Using our custom condition
my_log <- function(x, base = exp(1)) { if (!is.numeric(x)) { abort_bad_argument("x", must = "be numeric", not = x) } if (!is.numeric(base)) { abort_bad_argument("base", must = "be numeric", not = base) } base::log(x, base = base) } my_log(3, 'abc')
## `base` must be numeric; not character.
“The best error messages tell you what is wrong and point you in the right direction to fix the problem.”
“The goal is to make it as easy as possible for the user to find and fix the problem.”
tryCatch
.if-else
).Let’s write conditions for the code from the Riffomonas minimalR tutorial and work on a few exercises from AdvancedR.
R/baxter.R
get_metadata()
get_bmi()
get_bmi_category()
R/exercises.R
careful_remove()
check_dependencies()
bottles_of_beer()
Clone this repo
git clone https://github.com/SchlossLab/exception-handling
or if you previously cloned it, pull new commits:
cd path/to/repo/ ; git pull
Checkout a new branch
git checkout -b descriptive-branch-name
After modifying your part, commit your changes
git add . ; git commit -m "descriptive commit message"
Push your changes
git push -u origin descriptive-branch-name
Open a pull request on GitHub, mention your issue number(s), and merge it if there aren’t conflicts.
Relevant XKCDs: