Strange difference between x and get("x")?

r

Solution

This indeed turned out to be my C code. I knew TRUELENGTH is sometimes used by R but I didn't think on CHARSXP. When a variable name is the same as some character value, the CHARSXP's TRUELENGTH is used by R to hold an internal hash value, see main/envir.c. My SET_TRUELENGTH on the CHARSXP was clobbering the hash. Thanks to Simon Urbanek for explaining this, and thanks for all the tips and ideas in comments.

To demonstrate :

$ R --vanilla
R version 2.14.0 (2011-10-31)

> system("R CMD SHLIB -otest.so test.c")
> dyn.load("test.so")
> truelength = function(x)invisible(.Call("truelength",x))
> 
> truelength("A")
'A' has length 1 and truelength 0
> truelength("ABC")
'ABC' has length 3 and truelength 0
> A=123
> truelength("A")
'A' has length 1 and truelength 65    # 65 is the HASHPRI, for bound variable A
> truelength("ABC")
'ABC' has length 3 and truelength 0    # no variable ABC so truelength unused
> ABC=456
> truelength("ABC")
'ABC' has length 3 and truelength 17763   # now ABC symbol is bound
> 
> foo = 7
> truelength("foo")               
'foo' has length 3 and truelength 27999   # bound
> truelength("bar")               
'bar' has length 3 and truelength 0       # not bound
> .Internal(inspect("foo"))
@876eb08 16 STRSXP g0c1 [NAM(2)] (len=1, tl=0)   # tl=0 of STRSXP vector
  @81759e8 09 CHARSXP g0c1 [gp=0x21] "foo"       # tl of CHARSXP not shown by inspect

where the C code to see the TRUELENGTH of the CHARSXP is :

// test.c
#include <R.h>
#include <Rdefines.h> 

SEXP truelength(SEXP v)
{
    SEXP s = STRING_ELT(v,0);
    Rprintf("'%s' has length %d and truelength %d\n",
                  CHAR(s), LENGTH(s), TRUELENGTH(s));
    return(R_NilValue);
}

Problem

Somehow, sometimes, I'm ending up in a state like this : ``` > x [1] 1 2 3 > get("x") Error in get("x") : object 'x' not found > x [1] 1 2 3 ``` I can't reproduce it reliably. What sort of things might I have done wrong in my C code? Why would typing `x` at the prompt find it, but `get("x")` not? What's the difference internally between `x` and `get("x")`? Any hints much appreciated. I've started seeing this since R 2.14.0 but my C code has also been changing too. EDIT : reproducible example ``` // test.c #include <R.h> #include <Rdefines.h> SEXP test(SEXP df) { SEXP levels, s; int j; levels = getAttrib(VECTOR_ELT(df,0), R_LevelsSymbol); Rprintf("levels %u, type %d, length %d, truelength %d\n", levels,TYPEOF(levels),LENGTH(levels),TRUELENGTH(levels)); for (j=0; j<length(levels); j++) { s = STRING_ELT(levels,j); Rprintf("%d %d %s %u %d %d\n", length(levels), TYPEOF(s), CHAR(s), s, LENGTH(s), TRUELENGTH(s)); SET_TRUELENGTH(s,1); // clobbers the 65, but why 65 ("A") there? Rprintf("%d %d %s %u %d %d\n", length(levels), TYPEOF(s), CHAR(s), s, LENGTH(s), TRUELENGTH(s)); } return(R_NilValue); } ``` and to run it : ``` R --vanilla system("R CMD SHLIB -otest.so test.c") dyn.load("test.so") if (FALSE) A # needed for error to occur (!) DF <- data.frame(a = c("A", "Z"), b = 1:4) print(DF) .Call("test",DF) print(DF) A = data.frame() for (i in 1:100) { cat(i,"") assign(paste("v",i,sep=""),i) get("A") } ``` The output I get : ``` $ R --vanilla R version 2.14.0 (2011-10-31) # [snip header] > system("R CMD SHLIB -otest.so test.c") gcc -std=gnu99 -I/usr/share/R/include -fpic -std=c99 -O6 -Wall -Wno-unused -pedantic -c test.c -o test.o gcc -std=gnu99 -shared -o test.so test.o -otest.so -L/usr/lib/R/lib -lR > dyn.load("test.so") > > if (FALSE) A # needed for error to occur (!) > > DF <- data.frame(a = c("A", "Z"), b = 1:4) > print(DF) a b 1 A 1 2 Z 2 3 A 3 4 Z 4 > .Call("test",DF) levels 151395176, type 16, length 2, truelength 0 2 9 A 149596512 1 65 # why this 65 here? 2 9 A 149596512 1 1 2 9 Z 149596320 1 0 2 9 Z 149596320 1 1 NULL > print(DF) a b 1 A 1 2 Z 2 3 A 3 4 Z 4 > > A = data.frame() > for (i in 1:100) { + cat(i,"") + assign(paste("v",i,sep=""),i) + get("A") + } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Error in get("A") : object 'A' not found > > sessionInfo() R version 2.14.0 (2011-10-31) Platform: i686-pc-linux-gnu (32-bit) locale: [1] LC_CTYPE=en_GB.UTF-8 LC_NUMERIC=C [3] LC_TIME=en_GB.UTF-8 LC_COLLATE=en_GB.UTF-8 [5] LC_MONETARY=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8 [7] LC_PAPER=C LC_NAME=C [9] LC_ADDRESS=C LC_TELEPHONE=C [11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C attached base packages: [1] stats graphics grDevices utils datasets methods base > ``` Any ideas? If the `if (FALSE) A` line is commented out then it works fine. For repeated tests, R must be started fresh each time.

Original source