Reputation: 386
Description of stopifnot from R Documentation
Description
If any of the expressions in ... are not all TRUE, stop is called, producing an error message indicating the first of the elements of ... which were not true.
Usage
stopifnot(...)
Arguments
... any number of (logical) R expressions, which should evaluate to TRUE.
Sometimes the expressions in ... dont evaluate to TRUE. Consider the error message for the the below scenario
a <- 1:10
stopifnot(
class(a) %in% c("numeric", "integer"),
sum(a) >= 100
)
> Error: sum(a) >= 100 is not TRUE
which is fine. But, the error message for the the below scenario is not what I expect
a <- letters
stopifnot(
class(a) %in% c("numeric", "integer"),
sum(a) >= 100
)
> Error in sum(a) : invalid 'type' (character) of argument
I expect it to say
Error: class(a) %in% c("numeric", "integer") is not TRUE
But, it doesnt.
Are my expectations correct? Is that how stopifnot() is supposed to work? And how can I make stopifnot() work like that?
Upvotes: 1
Views: 762
Reputation: 57686
stopifnot
evaluates each of your supplied expressions, and then checks that all of them are TRUE
. If this isn't the case, it halts and prints an error message, saying which of the expressions failed.
In your example, what's happening is that the expressions themselves are triggering an error. It's the evaluation of the expression sum(a) >= 100
that results in the error message, not stopifnot
itself.
Upvotes: 2
Reputation: 386
I cant answer about how stopifnot() is supposed to work. But, here is how to achieve what is expected
Consider using the hadley's assertthat package. It works as expected
a <- letters
assertthat::assert_that(
class(a) %in% c("numeric", "integer"),
sum(a) >= 100
)
> Error: `%in%`(x = class(a), table = c("numeric", "integer")) is not TRUE
It also gives more useful error messages. The above error message is not a really good example of that. Consider the below scenario
a <- 1:10
assert_that(
class(a) %in% c("numeric", "integer"),
sum(a) >= 100
)
> Error: sum(a) not greater than or equal to 100
Also, here's how stopifnot() can be made to work like that. So, now for the same scenario
stopifnot <- function (...) {
ll <- lazyeval::lazy_dots(...)
n <- length(ll)
if (n == 0L) {
return(invisible())
}
mc <- match.call()
for (i in 1L:n) {
if (!(is.logical(r <- lazyeval::lazy_eval(ll[[i]])) && !anyNA(r) && all(r))) {
ch <- deparse(mc[[i + 1]], width.cutoff = 60L)
if (length(ch) > 1L) {
ch <- paste(ch[1L], "....")
}
stop(sprintf(ngettext(length(r), "%s is not TRUE", "%s are not all TRUE"), ch), call. = FALSE, domain = NA)
}
}
invisible()
}
a <- letters
stopifnot(
class(a) %in% c("numeric", "integer"),
sum(a) >= 100
)
> Error: class(a) %in% c("numeric", "integer") is not TRUE
Upvotes: 1