[R] how to modify variables of another frame (but not global)
Thomas Lumley
tlumley at u.washington.edu
Tue Mar 23 17:09:28 CET 2004
On Tue, 23 Mar 2004, Gabor Grothendieck wrote:
> > The second, f2, uses <<- which searches through its parent environments for the
> assigned-to variable. As can be seen in f2a near the end it appears to
> do the same thing as assign underneath as the entire z in f seems to
> have been copied over. Note that the right hand side of the assignment
> is still handled normally. QUESTION: Could someone explain what is
> going on in f2a in detail???
Someone has previously reported this as a bug; it's at least an infelicity.
The idea is that the RHS is evaluated in the local frame and the
assignment is then done in an enclosing frame. Now we get into how
assignment functions work.
a[1]<<-b[1]
like
a[1]<-b[1]
is really
a<-"[<-"(a,1,b)
So in your second example
z[1]<<-z[1]+1 is
z<<-"[<-"(z,1,z)
where the first z is the one in the enclosing environment and the second
is the local one.
Now what appears to happen is that R cleverly optimizes to avoid copying,
assigning the whole vector z rather than just the first element, since the
old z will be overwritten anyway. That is, the code to decide whether the
LHS and RHS are the same vector doesn't seem to be special-cased for <<-.
I'm not completely sure about this -- the code is complicated.
Simpler versions:
> z<-1:3
> local({w<-10:12; z[1]<<-w[1]+1})
> z
[1] 11 2 3
> z<-1:3
> local({z<-10:12; z[1]<<-z[1]+1})
> z
[1] 11 11 12
OTOH, one could reasonably argue that using z<<- when there is a local z
is asking for problems.
> The third, f3 uses eval.parent. It looks similar to <<- but its actually
> different. eval.parent evaluates the expression in the parent environment of f
> so it never looks within f. Both sides of the assignment are handled in the
> parent environment in this one. This can be seen in f3a where the z defined in
> f is completely ignored. I believe that eval.parent does modify individual
> cells without copying the entire structure. QUESTION: Is that right ???
It's potentially right. That is, in situations where z[1]<-z[1]+1 doesn't
copy, f3 won't copy.
I also note that in general <<- and eval.parent() are not related. It is
a bad idea to confuse the enclosing and parent environments, even though
they are often the same.
-thomas
> > # 1. assign and get
> >
> > f1 <- function() {
> + f <- function(x,k) {
> + xc <- as.character(substitute(x)) # character representation of name
> + x <- get( xc, parent.frame() )
> + x[1] <- x[1] + k
> + assign( xc, x, parent.frame() )
> + }
> + z <- 1:5
> + f(z,1)
> + print(z)
> + }
> > z <- 7
> > f1()
> [1] 2 2 3 4 5
> > z
> [1] 7
>
>
> > # 2. <<-
> >
> > f2 <- function() {
> + f <- function(x,k) eval(eval(substitute( x[1] <<- x[1] + k )))
> + z <- 1:5
> + f(z,1)
> + print(z)
> + }
> > z <- 7
> > f2()
> [1] 2 2 3 4 5
> > z
> [1] 7
> >
> > # 3. eval.parent
> >
> > f3 <- function() {
> + f <- function(x,k) eval(eval.parent(substitute(x[1] <- x[1] + k )))
> + z <- 1:5
> + f(z,1)
> + print(z)
> + }
> > z <- 7
> > f3()
> [1] 2 2 3 4 5
> > z
> [1] 7
>
>
> > # <<- with a local z
> >
> > f2a <- function() {
> + f <- function(x,k) {
> + z <- 10:12
> + eval(eval(substitute( x[1] <<- x[1] + k )))
> + }
> + z <- 1:5
> + f(z,1)
> + print(z)
> + }
> > z <- 7
> > f2a()
> [1] 11 11 12
> > z
> [1] 7
>
>
> > # eval parent with a local z
> >
> > f3a <- function() {
> + f <- function(x,k) {
> + z <- 10:12
> + eval(eval.parent(substitute(x[1] <- x[1] + k )))
> + }
> + z <- 1:5
> + f(z,1)
> + print(z)
> + }
> > z <- 7
> > f3a()
> [1] 2 2 3 4 5
> > z
> [1] 7
> >
>
> > R.version.string
> [1] "R version 1.8.1, 2003-11-21"
>
> ------------------------------------------------------
>
> Here is a copy of just the input
>
>
>
> # 1. assign and get
>
> f1 <- function() {
> f <- function(x,k) {
> xc <- as.character(substitute(x)) # character representation of name
> x <- get( xc, parent.frame() )
> x[1] <- x[1] + k
> assign( xc, x, parent.frame() )
> }
> z <- 1:5
> f(z,1)
> print(z)
> }
> z <- 7
> f1()
> z
>
> # 2. <<-
>
> f2 <- function() {
> f <- function(x,k) eval(eval(substitute( x[1] <<- x[1] + k )))
> z <- 1:5
> f(z,1)
> print(z)
> }
> z <- 7
> f2()
> z
>
> # 3. eval.parent
>
> f3 <- function() {
> f <- function(x,k) eval(eval.parent(substitute(x[1] <- x[1] + k )))
> z <- 1:5
> f(z,1)
> print(z)
> }
> z <- 7
> f3()
> z
>
> # <<- with a local z
>
> f2a <- function() {
> f <- function(x,k) {
> z <- 10:12
> eval(eval(substitute( x[1] <<- x[1] + k )))
> }
> z <- 1:5
> f(z,1)
> print(z)
> }
> z <- 7
> f2a()
> z
>
> # eval parent with a local z
>
> f3a <- function() {
> f <- function(x,k) {
> z <- 10:12
> eval(eval.parent(substitute(x[1] <- x[1] + k )))
> }
> z <- 1:5
> f(z,1)
> print(z)
> }
> z <- 7
> f3a()
> z
>
> R.version.string
>
> ---
>
> Date: Tue, 23 Mar 2004 12:17:39 +0100
> From: Meinhard Ploner <meinhardploner at gmx.net>
> To: <r-help at stat.math.ethz.ch>
> Subject: [R] how to modify variables of another frame (but not global)
>
>
> Hello!
>
> Maybe "frame" is not the right term in this context.
> I explain my problem by example code:
>
> fun2 <- function(objName, add) {
> ## the object "objName" should be increased by "add",
> ## but the evaluation should be done in the calling function (here:
> fun1)
> ## ...... what's the right code??
> }
>
> fun1 <- function() {
> x <- 1
>
> fun2("x", 10) ## should modify "x"
>
> ## now x should be 11, but only here and NOT globally!
> ...
> }
>
>
> I would like to appreciate any solution!
> Thanks in advance
>
> Meinhard Ploner
>
> ______________________________________________
> R-help at stat.math.ethz.ch mailing list
> https://www.stat.math.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html
>
Thomas Lumley Assoc. Professor, Biostatistics
tlumley at u.washington.edu University of Washington, Seattle
More information about the R-help
mailing list