Kun Ren
Kun Ren

Reputation: 5013

Wrapper function for data.table does not work in local environment

Consider the following function:

test <- function(x,...) {
  # in practical case, it does more
  x[...]
}

Then the wrapper function that calls subsetting does not work in a local environment.

> library(data.table)
> m <- data.table(x=1:3,key="x")
> m[J(1)]
   x
1: 1
> local({i <- 1; m[J(i)]})
   x
1: 1
> local({i <- 1; test(m, J(i))})
Error in eval(expr, envir, enclos) : object 'i' not found
> local({i <- 1; test(m, i)})
Error in eval(expr, envir, enclos) : object 'i' not found

It is probably because test() does not try find symbols in that environment. However, if I change data.table to data.frame and run the last line, it works fine.

> m <- data.frame(x=1:3)
> local({i <- 1; test(m, i)})
  x
1 1
2 2
3 3

How can I modify test() so that it can work with ... and subsetting for data.table?

My session info:

> sessionInfo()
R version 3.1.1 (2014-07-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.9.2

loaded via a namespace (and not attached):
[1] plyr_1.8.1    Rcpp_0.11.2   reshape2_1.4  stringr_0.6.2 tools_3.1.1  

Upvotes: 2

Views: 303

Answers (1)

MrFlick
MrFlick

Reputation: 206506

It makes sense that it wouldn't work because the [...] for data.table takes an expression that's evaluated in the parent.frame. So in this case J(i) would be evaluated in the environment of test() since that's where it's called from. Since test() is defined in the global environment, any variables not found in test() will be searched for in the global environment by default. The test() function is not really related to the local environment you've created. You could change the test() function to be evaluated in it's parent.frame. For example

test <- function(x,...) {
    cc <- match.call()
    cc[[1]] <- quote(`[`)
    names(cc)[2]<-"" #make data.frame happy
    eval.parent(cc)
}

Test data

library(data.table)
m <- data.table(x=1:3,key="x")    
n <- data.frame(x=1:3)

And now the function

local({i <- 1; m[J(i)]})
#    x
# 1: 1

local({i <- 1; test(m, J(i))})
#    x
# 1: 1

local({i <- 1; test(n, i)})
#   x
# 1 1
# 2 2
# 3 3

i<-2
test(m, J(i))
#    x
# 1: 2

Upvotes: 5

Related Questions