Condition handling

Colin Fay

2018-04-20

warnings and messages

The stop_if, warn_if and message_if are easy to use functions that send an error, a warning or a message if a condition is met. Each function has its counterpart with _not. That returns a message if the condition is not met.

stop_if_not is quite the same as assert_that from the {assertthat} package, except that it can takes mappers. It is not the same as base stopifnot(), as it doesn’t take a list of expression.

These functions are also flexible as you can pass base predicates (is.numeric, is.character…), a custom predicate built with mappers, or even your own testing function.

You can either choose a custom message or just let the built-in messages be printed:

x <- 12
# Stop if .x is numeric
stop_if(.x = x, 
        .p = is.numeric)
#> Error: Test `is.numeric` on `x` returned an error.

y <- "20"
# stop if .x is not numeric
stop_if_not(.x = y, 
            .p = is.numeric, 
            msg = "y should be numeric")
#> Error: y should be numeric
a  <- "this is not numeric"
# Warn if .x is charcter
warn_if(.x = a, 
        .p = is.character)
#> Warning: Test `is.character` on `a` returned a warning.

b  <- 20
# Warn if .x is not equal to 10
warn_if_not(.x = b, 
        .p = ~ .x == 10 , 
        msg = "b should be 10")
#> Warning: b should be 10

c <- "a"
# Message if c is a character
message_if(.x = c, 
           .p = is.character, 
           msg = "You entered a character element")
#> You entered a character element

# Build more complex predicates
d <- 100
message_if(.x = d, 
           .p = ~ sqrt(.x) < 42, 
           msg = "The square root of your element must be more than 42")
#> The square root of your element must be more than 42

# Or, if you're kind of old school, you can still pass classic functions

e <- 30
message_if(.x = e, 
           .p = function(vec){
             return(sqrt(vec) < 42)
           }, 
           msg = "The square root of your element must be more than 42")
#> The square root of your element must be more than 42

If you need to call a function that takes no argument at .p, use this function as .x.

true <- function() TRUE
false <- function() FALSE
stop_if(.x =  true(), msg = "This is true")
#> Error: This is true

warn_if_not(false(), 
            msg = "This is false")
#> Warning: This is false

message_if(.x = true(), 
            msg = "Huray!")
#> Huray!

If you don’t specify a .p, the default test is isTRUE.

a <- is.na(airquality$Ozone)
message_if_any(a, msg = "NA found")
#> NA found

In function

That can come really handy inside a function :

none, all, any

stop_if, warn_if and message_if all have complementary tests with _all, _any and _none, which combine the if_* and the warn_*, stop_* and message_* seen before. They take a list as first argument, and a predicate. They test if any, all or none of the elements validate the predicate.