7

So, I discovered this:

> TRUE == "TRUE"
[1] TRUE
> TRUE == "BOO"
[1] FALSE
> TRUE == "true"
[1] FALSE
> TRUE == "T"
[1] FALSE
> FALSE == "FALSE"
[1] TRUE
> FALSE == "F"
[1] FALSE

According to the R documentation for logical {base}:

as.logical attempts to coerce its argument to be of logical type. Character strings c("T", "TRUE", "True", "true") are regarded as true, c("F", "FALSE", "False", "false") as false, and all others as NA.

This is actually the case:

> as.logical("T")
[1] TRUE

So apparently, what's going on with TRUE == "T" is not an as.logical sort of conversion. Is there any reasonable explanation for the behavior of these == comparisons?

turtlegraphics
  • 296
  • 3
  • 8
  • `TRUE == T #[1] TRUE` The `"T"` can be anything. BTW, it is better to TRUE instead of the abbreviated T as it can lead to some problems – akrun Dec 04 '16 at 07:56
  • Commenting here so it also goes to @akrun.. he might be able to help better. Here's something I tied, but am at a loss to interpret the output : `trace ("=="); "TRUE"==T` > Though it seems my interpretation of the documentation was correct, further insight would be helpful. – R.S. Dec 04 '16 at 08:14
  • May be off topic, but there is function `isTRUE` to be used in cases where the answer has to be TRUE only and only when it is identical to TRUE, anything else resulting in FALSE (even the vectors of TRUE). – Petr Matousu Dec 04 '16 at 09:41

3 Answers3

4

Here's what I made of it: From the documentation of logical comparisons ?"==":

At least one of x and y must be an atomic vector, but if the other is a list R attempts to coerce it to the type of the atomic vector: this will succeed if the list is made up of elements of length one that can be coerced to the correct type. If the two arguments are atomic vectors of different types, one is coerced to the type of the other, the (decreasing) order of precedence being character, complex, numeric, integer, logical and raw.

To me it seems like the latter part of this is at work here. TRUE is being coerced to "TRUE" and the actual comparison becomes "TRUE"=="TRUE" instead of TRUE==TRUE.

T always gets converted to TRUE so T=="TRUE" holds. However ``"T"` has no such luck when conversion is to happen to.character and not to.logical. .

R.S.
  • 2,093
  • 14
  • 29
  • Of course, that's it! Are there any other languages which would coerce a boolean to a string and then compare? My god, the horror. – turtlegraphics Dec 04 '16 at 08:06
  • yeah, you find R zombies in the backyard everyday :-) BTW, I was going to add that the veracity of my interpretation depends on the meaning of `decreasing order` in that sentence.. someone should be able to trace how the conversion is actually taking place. How does one do that? – R.S. Dec 04 '16 at 08:09
  • 1
    No zombies at all, you have to compare apples with apples, that is it. – Petr Matousu Dec 04 '16 at 10:11
3

In terms of your question I'm having trouble imagining a scenario in which you would evaluate TRUE == "TRUE", vs "TRUE" == TRUE. For instance; take a wrapper function that we can run all scenarios for your variables and iterate them through tests for as.logical, is.logical, x == TRUE, x == FALSE, x != TRUE etc...

What our testing function will do is take an input and only return the scenarios that evaluate to TRUE in terms of a logical test in an R function.

f <-function(var){
  do_fun <- list(
    `%s == TRUE` = function(x)x==TRUE,
    `%s == FALSE` = function(x)x == FALSE,
    `as.logical(%s)` = function(x)as.logical(x),
    `is.logical(%s)` = function(x)is.logical(x))

  a <- sapply(names(do_fun), function(i){
    do.call(do_fun[[i]],list(var))
  })
  set_name <- sprintf(names(a),var)
  a <- as.list(a)
  names(a) <- set_name
  a[sapply(a,`[`,1)]

}

Testing on TRUE

# from base test to show
> is.logical(TRUE)
[1] TRUE

Now with our testing fun

> f(TRUE)
$`TRUE == TRUE`
[1] TRUE

$`as.logical(TRUE)`
[1] TRUE

$`is.logical(TRUE)`
[1] TRUE

As strings instead of reserved characters

> f("true")
$`as.logical("true")`
[1] TRUE

> f("TRUE")
$`"TRUE" == TRUE`
[1] TRUE

$`as.logical("TRUE")`
[1] TRUE

On numeric values the output logical is based on the evaluation of the input rather than the class

> f(10.1)
$`as.logical(10.1)`
[1] TRUE

> f(10.1 > 1)
$`TRUE == TRUE`
[1] TRUE

$`as.logical(TRUE)`
[1] TRUE

$`is.logical(TRUE)`
[1] TRUE

or

> f(1+1)
$`as.logical(2)`
[1] TRUE
Carl Boneri
  • 2,632
  • 1
  • 13
  • 15
  • 1
    Cool examples, thanks! I also have trouble imagining a real use of this, but I'm teaching a stat class in which a student actually did use "TRUE" instead of TRUE all over his code, and I was gobsmacked when it worked. – turtlegraphics Dec 04 '16 at 19:11
  • yeah there is no use for this other than probably instructional haha. also wrote half asleep... but the evaluation into the names could be useful somehow...just haven't thought through – Carl Boneri Dec 04 '16 at 19:13
1

Better to use isTRUE

> isTRUE 
function (x) 
identical(TRUE, x)
<bytecode: 0x82228c8>
<environment: namespace:base>

> isTRUE("T")
[1] FALSE
> isTRUE(T)
[1] TRUE
> isTRUE(TRUE)
[1] TRUE
> isTRUE("TRUE")
[1] FALSE 
> isTRUE("anything")
[1] FALSE
> isTRUE(1L)
[1] FALSE
> isTRUE(c(TRUE,TRUE))
[1] FALSE
> 
> isTRUE(any(c(TRUE,TRUE)))
[1] TRUE
> isTRUE(all(c(TRUE,TRUE)))
[1] TRUE

> answer <- "yes"
> isTRUE(answer %in% c("Y","Yes","y","yes"))
[1] TRUE
> answer <- "no"
> isTRUE(answer %in% c("Y","Yes","y","yes"))
[1] FALSE
> answer <- c("Y","n")
> isTRUE(answer %in% c("Y","Yes","y","yes"))
[1] FALSE
Petr Matousu
  • 3,120
  • 1
  • 20
  • 32