Today I found that some of my stopifnot()
tests are failing because the passed arguments evaluate to empty logical vectors.
Here is an example:
stopifnot(iris$nosuchcolumn == 2) # passes without error
This is very unintuitive and seems to contradict a few other behaviours. Consider:
isTRUE(logical())
> FALSE
stopifnot(logical())
# passes
So stopifnot()
passes even when this argument is not TRUE
.
But furthermore, the behaviour of the above is different with different types of empty vectors.
isTRUE(numeric())
> FALSE
stopifnot(numeric())
# Error: numeric() are not all TRUE
Is there some logic to the above, or should this be considered a bug?
Other answers cover the practical reasons why stopifnot
behaves the way it does; but I agree with Karolis that the thread linked by Henrik adds the real explanation of why this is the case:
As author stopifnot(), I do agree with [OP]'s "gut feeling" [...] that
stopifnot(dim(x) == c(3,4))
[...][should] stop in the case where x is a simple vector instead of a matrix/data.frame/... with dimensionsc(3,4)
... but [...] the gut feeling is wrong because of the fundamental lemma of logic: [...]"All statements about elements of the empty set are true"
Martin Maechler, ETH Zurich
Also, [...], any() is to "|" what sum() is to "+" and what all() is to "&" and prod() is to "*". All the operators have an identity element, namely FALSE, 0, TRUE, and 1 respectively, and the generic convention is that for an empty vector, we return the identity element, for the reason given above.
Peter D.