-
-
Save wrathematics/c3e5225cf56596b31e01f717e8675640 to your computer and use it in GitHub Desktop.
library(inline) | |
csrc = " | |
SEXP ret; | |
PROTECT(ret = allocVector(LGLSXP, 2)); | |
LOGICAL(ret)[0] = 1; | |
LOGICAL(ret)[1] = -1; | |
UNPROTECT(1); | |
return ret; | |
" | |
example_vec = cfunction(body=csrc) | |
vec1 = example_vec() | |
vec2 = c(TRUE, TRUE) | |
vec1 | |
## [1] TRUE TRUE | |
vec2 | |
## [1] TRUE TRUE | |
identical(vec1, vec2) | |
## [1] FALSE | |
all.equal(vec1, vec2) | |
## [1] "1 element mismatch" | |
vec1 == vec2 | |
## [1] TRUE FALSE | |
for (i in 1:length(vec1)) print(vec1[i] == vec2[i]) | |
## [1] TRUE | |
## [1] TRUE |
Looks like base:::all.equal.default calls down to base:::all.equal.raw for the logical case, so it is actually checking bytes.
Also:
> as.integer(vec1)
[1] 1 -1
> as.integer(vec2)
[1] 1 1
> as.integer(vec1[2])
[1] 1
> as.integer(vec1[2:1])
[1] -1 1
> as.integer(vec1[1:2])
[1] 1 -1
So subsetting is normalizing the logical value somewhere when the index is only 1 (i.e. a scalar is returned) but not otherwise. I would conjecture, without having taken the time to track it down, that this is happening in some sort of scalar fast path.
I'm sure you know, though, that you invalidated the logical vector when you used its pointer to give an element a value other than TRUE or FALSE in the Rboolean, or NA_INTEGER (i.e. INT_MIN). My guess is that the behavior is formally undefined when that happens, so it's surprising, but also not really, imho.
The scalar case is because of special handling by [
, as you conjectured.
(╯°□°)╯︵ ┻━┻)
wat