[R] side-effects in functions that replace object values andattributes
William Dunlap
wdunlap at tibco.com
Wed Feb 17 02:50:38 CET 2010
> -----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