How can all (`all`) be true while none (`any`) are true at the same time?

Viewed 96
a <- character()
b <- "SO is great"

any(a == b) 
#> [1] FALSE

all(a == b)
#> [1] TRUE

The manual describes ‘any’ like this Given a set of logical vectors, is at least one of the values true? So, not even one value in the comparison a == b yields TRUE. If that is the case how can ‘any’ return FALSE while ‘all’ returns TRUE? ‘all’ is described as Given a set of logical vectors, are all of the values true?.

In a nutshell: all values are TRUE and none are TRUE at the same time? I am not expert but that looks odd.

Questions:

  1. Is there a reasonable explanation for or is it just some quirk of R?

  2. What are the ways around this?

Created on 2021-01-08 by the reprex package (v0.3.0)

4 Answers

Regarding question number 2, I know of identical. It works well in all the situations I can think of.

a <- "a"
b <- "b"
identical(a, b) # FALSE >> works
#> [1] FALSE

a <- character(0)
identical(a, b) # FALSE >> works
#> [1] FALSE

a <- NA
identical(a, b) # FALSE >> works
#> [1] FALSE

a <- NULL
identical(a, b) # FALSE >> works
#> [1] FALSE

a <- b
identical(a, b) # TRUE >> works
#> [1] TRUE

identical seems to be a good workaround though it still feels like a workaround to a part-time developer like me. Are there more solutions? Better ones? And why does R behave like this in the first place (see question)?

Created on 2021-01-08 by the reprex package (v0.3.0)

Usually, when comparing a == b the elements of the shorter vector are recycled as necessary. However, in your case a has no elements, so no recycling occurs and the result is an empty logical vector.

The results of any(a == b) and all(a == b) are coherent with the logical quantifiers for all and exists. If you quantify on an empty range, for all gives the neutral element for logical conjunction (AND) which is TRUE, while exists gives the neutral element for logical disjunction (OR) which is FALSE.

As to how avoid these situations, check if the vectors have the same size, since comparing vectors of different lengths rarely makes sense.

Regarding question 1) I have no idea whether I am correct, but here are my thoughts:

In R all() is the compliment of any(). For consistency, all(logical(0)) is true. So, you're situation you are capturing this unique case.

In mathematics, this is analogous to a set being both open and closed. I'm not a computer scientist, so I can't really talk to why one of the greybeards from way back when implemented this in either R or S.

regarding question 2) I think the other responses have answered this well.

Another solution provided by the shiny package is isTruthy(). The package introduced the concept of truthy/falsy that “generally indicates whether a value, when coerced to a base::logical(), is TRUE or FALSE” (see the documentation).

require(shiny, quietly = TRUE)

a <- "a"
b <- "b"
isTruthy(a == b) # FALSE >> works
#> [1] FALSE

a <- character(0)
isTruthy(a == b) # FALSE >> works
#> [1] FALSE

a <- NA
isTruthy(a == b) # FALSE >> works
#> [1] FALSE

a <- NULL
isTruthy(a == b) # FALSE >> works
#> [1] FALSE

a <- b
isTruthy(a == b) # TRUE >> works
#> [1] TRUE

One of the advantages is that you can use other operators like %in% or match(), too.

The situation in R is that you never know what a function will return when it fails. Some functions return NA, others NULL, and yet others vectors with length == 0. isTruthy() makes it easier to handle the diversity.

Unfortunately, when one does not write a shiny app it hardly makes sense to load the package because - aside from isTruthy - shiny only adds a large bunch of unneeded Web App features.

Created on 2021-01-10 by the reprex package (v0.3.0)

Related