4

I am reading the http://www.cran.r-project.org/doc/manuals/R-lang.pdf manual chapter 4.3 and I just don't get it. Maybe someone can give me a quick explanation why R behaves in the following way.

fCall <- function(i){       
    dtData[i]   
}

fSubstituteCall <- function(i){     
    iSub <- substitute(i)   
    dtData[eval(iSub)]  
}


library(data.table)
dtData <- data.table(id=LETTERS, value=1:26)
dtData[id == 'C']           #works
fCall(id == 'C')            #Error in eval(expr, envir, enclos) : object 'id'     not found
fSubstituteCall(id == 'C')  #works

Why does fSubstituteCall work and fCall not? Does it have to do with the evaluation of i? Or is it actually something specific to data.table package?

EDIT:

Thank you so far for your answers. I kind of get it and I agree that it is a duplicate of stackoverflow.com/q/14837902/602276. So I am going to simplify my question.

How do I make fPrintArgument print the argument i as a string? So in the case fCall('C') it should print out the string 'C', and in the fCall(id == 'C') it should print out the string 'id == "C"'.

Is this possible?

fPrintArgument <- function(i){
#This is what i have come up with so far, but it doesn't work       
    print(deparse(substitute(i)))
    print(deparse((i)))
}

fCall <- function(x){   
    fPrintArgument(x)   
}

fCall('C')
fCall(id == 'C')
Wolfgang Wu
  • 834
  • 6
  • 16
  • 3
    In an indirect way, your question is a duplicate of http://stackoverflow.com/q/14837902/602276, where I ask pretty much the same question, using different words. – Andrie Aug 28 '13 at 12:31
  • If you do this with a non-`data.table` vector, you'll see the difference in behavior. – Carl Witthoft Aug 28 '13 at 13:31
  • @CarlWitthoft, what do you mean? Using an atomic vector, the symbol `id` will remain unresolved. – Ferdinand.kraft Aug 28 '13 at 13:42
  • 1
    @Ferdinand.kraft I just meant to try the basic `function(i){myvector[i]}` and ditto for `function(i){isub<-sutstitute(i);myvector[i]}` – Carl Witthoft Aug 28 '13 at 14:47
  • @CarlWitthoft, I think the issue here is subtler than that. He is not passing the unevaluated expression `id=='C'` to `[.data.table`, he is passing `eval(iSub)`. Somehow, `[.data.table` executes `eval(...)` in a context where `id` makes sense, so that it works. This does not happen with `[.default`. – Ferdinand.kraft Aug 28 '13 at 20:03
  • 2
    @Ferdinand.kraft -`[.data.table` massages the `i` (and `j`) arguments, and deals with them specially when the leading call is `eval` – mnel Aug 28 '13 at 23:16
  • @mnel, Now it is starting to make sense :-) – Ferdinand.kraft Aug 29 '13 at 00:23
  • `eval(parse(text=paste(< construct whole DT query >)))` can sometimes be an easier way to construct dynamic queries. I think of this as analogous to dynamic SQL. See http://stackoverflow.com/a/11867624/403310 and http://stackoverflow.com/a/10676138/403310. – Matt Dowle Aug 29 '13 at 11:46
  • Does this answer your question? [How to write a function that calls a function that calls data.table?](https://stackoverflow.com/questions/14837902/how-to-write-a-function-that-calls-a-function-that-calls-data-table) – jangorecki Nov 21 '20 at 15:01

1 Answers1

0

Is it what you're looking for ?

fPrintArgument <- function(i) {
  cc <- sys.call(sys.parent(1))
  print(deparse(cc[[2]]))
}
fCall <- function(x){   
  fPrintArgument(x)   
}
fCall('C')
fCall(id == 'C')
Karl Forner
  • 4,175
  • 25
  • 32