[datatable-help] which parent.frame is more correct

Matthew Dowle mdowle at mdowle.plus.com
Mon Mar 4 01:56:33 CET 2013


Hi,

In general it's probably best to use a unique name like "..tmpvar" and 
let `i` or `j` find that via scope.
Passing a specific n to parent.frame(n) might work now, but may be 
dependent on data.table internals not changing in the future.
Also, note the Notes in ?parent.frame (i.e. user beware).

With those caveats out of the way, some answers inline ...

On 03.03.2013 23:47, Michael Nelson wrote:
> In answering http://stackoverflow.com/a/15102156/1385941
>
> I confidently stated at parent.frame(3) was the correct frame to use,
> and I stand by that, but am slightly confused over how parent.frame 1
> and 3 differ in how they are evaluated.
>
> More specifically, I don't understand why `parent.frame(1)` works as
> it does.
>
> Take for example
>
> x <- 3:4
>
> dt <- data.table(x = 1:5,y=5:1, key = 'x')
>
> foo <-function(){
>   x <- 1:2
>   for(n in 1:5) {
>     print(dt[list(get('x',parent.frame(n)))])
>   }
> }
>
> foo()
>
> # n= 1
> # uses parent.frame of foo
> #
> #    x y
> # 1: 3 3
> # 2: 4 2

Setting get(...,inherits=FALSE) reveals x isn't in parent.frame(1). 
That's base::eval itself ([.data.table internals call eval directly). 
get(...,inherits=TRUE) then finds "x" in .GlobalEnv via search().

>
> # n= 2
> # some kind of self join of  data.table
> # output equivalent of (dt[dt[list(x)]])
>
> #    x y y.1
> # 1: 1 5   5
> # 2: 2 4   4
> # 3: 3 3   3
> # 4: 4 2   2
> # 5: 5 1   1

That's picking up the "x" column name in dt. Because the eval inside 
[.data.table passes x to it. In other words, the normal place variables 
in i are looked for.

> # n= 3
> # uses parent.frame of call to `[.data.table`

Yes, I think so. I'm not always certain myself. I don't use 
parent.frame(3) but seems it works.

>
> #    x y
> # 1: 1 5
> # 2: 2 4
>

> # n >= 4
> # uses parent.frame of foo again (makes sense I think)
> #    x y
> # 1: 5 1
> # 2: 4 2


If you need to refer to a specific scope without using parent.frame(n), 
this might be safer :


foo <-function(){
   x <- 1:2
   ..localenv = environment()
   print(dt[list(get('x',..localenv,inherits=FALSE))])
}

which is what ..() is intended to do in future built in :

foo <-function(){
   x <- 1:2
   print(dt[..(x)])
}


But currently I prefer doing :

foo <-function(){
   ..x <- 1:2
   print(dt[list(..x)])
}

which is what I meant at the top:  in general it's probably best to use 
a unique name like ..tmpvar and let `i` or `j` find that via scope.

Matthew




More information about the datatable-help mailing list