[R] side-effects in functions that replace object values andattributes
Stephen Tucker
brown_emu at yahoo.com
Wed Feb 17 16:20:17 CET 2010
Hi Bill, thanks for your response. There are many cases in which I find direct use of `names<-`, `mode<-`, `body<-`, `[<-`, `[[<-`, `$<-`, etc. to be helpful... so wrapping each function individually seems a bit verbose. Thanks for pointing out the compatibility with S-Plus - that was originally not a concern of mine but I suppose one should keep this in mind. So I propose two solutions, in addition to yours, and wonder if you or others have additional thoughts regarding this issue. Starting with the original problem:
> x <- 1:3
> `names<-`(x,letters[1:3])
a b c
1 2 3
> x
a b c
1 2 3
(the modification of the original variable, x, is undesirable - how to prevent it?)
--- solution 1) force evaluation within the function environment using force(). (perhaps still not S-Plus friendly)
> x <- 1:3
> `names<-`(force(x),letters[1:3])
a b c
1 2 3
> x
[1] 1 2 3
--- solution 2) wrap it in a general function, Funcall(), which will evaluate all arguments into a list before function application. (S-Plus friendly?)
> Funcall <- function(f,...)
+ do.call(f,list(...))
> x <- 1:3
> Funcall(`names<-`,x,letters[1:3])
a b c
1 2 3
> x
[1] 1 2 3
----- Original Message ----
From: William Dunlap <wdunlap at tibco.com>
To: Stephen Tucker <brown_emu at yahoo.com>; r-help at r-project.org
Sent: Tue, February 16, 2010 5:50:38 PM
Subject: RE: [R] side-effects in functions that replace object values andattributes
> -----Original Message-----
> From: r-help-bounces at r-project.org
> [mailto:r-help-bounces at r-project.org] On Behalf Of Stephen Tucker
> Sent: Tuesday, February 16, 2010 5:32 PM
> To: r-help at r-project.org
> Subject: [R] side-effects in functions that replace object
> values andattributes
>
> Hello list,
>
> I encountered some surprising behavior in R and wanted to
> check to see if I was imagining things. Previously, I thought
> that replacement/setter operators in prefix notation (e.g.,
> `[<-`(x,1,y) rather than x[1] <- y) did not produce side
> effects (i.e., left 'x' unchanged), but just realized that
> this is not the case anymore (or has it always been this way?
> - I don't have access to old R distributions at the moment,
> but using R 2.10.1 on Ubuntu and OS X)? I went through the
> NEWS file but did not see a change documented if there was
> one, but just going by my recollection...
>
> In any case, my understanding was that when modifying a value
> or attribute of an object, R reassigned the modified object
> to the original symbol. For instance, the help file for
> `name<-`() says that
>
> > names(z)[3] <- "c2"
>
> is evaluated as
>
> > z <- "names<-"(z, "[<-"(names(z), 3, "c2"))
>
> But the final (re)assignment (`<-`) seems redundant as
>
> > invisible("names<-"(z, "[<-"(names(z), 3, "c2")))
>
> does the same thing.
>
> In this case, I wonder if there is a preferred way to use the
> replacement/setter operators in prefix notation without
> producing such side effects
I would never recommend using replacement operators
this way. In part this is because S+ doesn't like it:
S+> x<-1:10
S+> `[<-`(x, 1, value=66.6)
[1] 66.6 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
Warning messages:
looks like the internal reference count was not updated in: x[1] <-
66.6
S+> x
[1] 1 2 3 4 5 6 7 8 9 10
in part because it is ugly, but mostly it is because
forcing the program to accept such usage closes off,
or at least restricts, an avenue for saving memory when
doing replacement operations.
If you have a replacement function that you are tempted
to use in this way, I recommend that you write a wrapper
function for it. E.g., instead of using
namedX <- `names<-`(x, value=as.character(x))
write
setNames <- function(x, names) {
names(x) <- names
x
}
and use it as
namesX <- setNames(x, as.character(x))
Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
> (replace() exists for `[<-`() and
> `[[<-`(), but perhaps something more general). For instance,
> if I did not desire the following modification in x:
>
> > x <- c("1","2")
> > y <- `names<-`(x,c("a","b"))
> > y
> a b
> "1" "2"
> > x
> a b
> "1" "2"
> >
>
> I might take advantage of R's lazy evaluation and use create
> a copy in the local function environment and allow that copy
> to be modified:
>
> > x <- c("1","2")
> > y <- `names<-`(`<-`(x,x),c("a","b"))
> > y
> a b
> "1" "2"
> > x
> [1] "1" "2"
>
> The interesting thing is that `mode<-`(), while also a
> "setter" function in that it sets an object attribute, does
> not behave as `names<-`():
>
> > x <- c("1","2")
> > y <- `mode<-`(x,"integer")
> > y
> [1] 1 2
> > x
> [1] "1" "2"
> > mode(x)
> [1] "character"
>
> So another question that naturally arises is whether there a
> general rule by which we can predict the behavior of these
> types of operators (whether they produce side effects or not)?
>
> Thanks,
>
> Stephen
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide
> http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>
More information about the R-help
mailing list