cnd_inherits: Does a condition or its ancestors inherit from a class?

View source: R/cnd.R

cnd_inheritsR Documentation

Does a condition or its ancestors inherit from a class?

Description

Like any R objects, errors captured with catchers like tryCatch() have a class() which you can test with inherits(). However, with chained errors, the class of a captured error might be different than the error that was originally signalled. Use cnd_inherits() to detect whether an error or any of its parent inherits from a class.

Whereas inherits() tells you whether an object is a particular kind of error, cnd_inherits() answers the question whether an object is a particular kind of error or has been caused by such an error.

Some chained conditions carry parents that are not inherited. See the .inherit argument of abort(), warn(), and inform().

Usage

cnd_inherits(cnd, class)

Arguments

cnd

A condition to test.

class

A class passed to inherits().

Capture an error with cnd_inherits()

Error catchers like tryCatch() and try_fetch() can only match the class of a condition, not the class of its parents. To match a class across the ancestry of an error, you'll need a bit of craftiness.

Ancestry matching can't be done with tryCatch() at all so you'll need to switch to withCallingHandlers(). Alternatively, you can use the experimental rlang function try_fetch() which is able to perform the roles of both tryCatch() and withCallingHandlers().

withCallingHandlers()

Unlike tryCatch(), withCallingHandlers() does not capture an error. If you don't explicitly jump with an error or a value throw, nothing happens.

Since we don't want to throw an error, we'll throw a value using callCC():

f <- function() {
  parent <- error_cnd("bar", message = "Bar")
  abort("Foo", parent = parent)
}

cnd <- callCC(function(throw) {
  withCallingHandlers(
    f(),
    error = function(x) if (cnd_inherits(x, "bar")) throw(x)
  )
})

class(cnd)
#> [1] "rlang_error" "error"       "condition"
class(cnd$parent)
#> [1] "bar"         "rlang_error" "error"       "condition"

try_fetch()

This pattern is easier with try_fetch(). Like withCallingHandlers(), it doesn't capture a matching error right away. Instead, it captures it only if the handler doesn't return a zap() value.

cnd <- try_fetch(
  f(),
  error = function(x) if (cnd_inherits(x, "bar")) x else zap()
)

class(cnd)
#> [1] "rlang_error" "error"       "condition"
class(cnd$parent)
#> [1] "bar"         "rlang_error" "error"       "condition"

Note that try_fetch() uses cnd_inherits() internally. This makes it very easy to match a parent condition:

cnd <- try_fetch(
  f(),
  bar = function(x) x
)

# This is the parent
class(cnd)
#> [1] "bar"         "rlang_error" "error"       "condition"

hadley/rlang documentation built on Dec. 17, 2024, 3:26 a.m.