From P.Dalgaard at biostat.ku.dk  Tue Mar 10 16:10:49 2009
From: P.Dalgaard at biostat.ku.dk (Peter Dalgaard)
Date: Tue, 10 Mar 2009 16:10:49 +0100
Subject: [Rd] surprising behaviour of names<-
In-Reply-To: <49B67CB1.8060005@idi.ntnu.no>
References: <49B67CB1.8060005@idi.ntnu.no>
Message-ID: <49B682F9.8050307@biostat.ku.dk>

Wacek Kusnierczyk wrote:
> playing with 'names<-', i observed the following:
>   
>     x = 1
>     names(x)
>     # NULL
>     'names<-'(x, 'foo')
>     # c(foo=1)
>     names(x)
>     # NULL
> 
> where 'names<-' has a functional flavour (does not change x), but:
> 
>     x = 1:2
>     names(x)
>     # NULL
>     'names<-'(x, 'foo')
>     # c(foo=1, 2)
>     names(x)
>     # "foo" NA
>   
> where 'names<-' seems to perform a side effect on x (destructively
> modifies x).  furthermore:
> 
>     x = c(foo=1)
>     names(x)
>     # "foo"
>     'names<-'(x, NULL)
>     names(x)
>     # NULL
>     'names<-'(x, 'bar')
>     names(x)
>     # "bar" !!!
> 
>     x = c(foo=1)
>     names(x)
>     # "foo"
>     'names<-'(x, 'bar')
>     names(x)
>     # "bar" !!!
> 
> where 'names<-' is not only able to destructively remove names from x,
> but also destructively add or modify them (quite unlike in the first
> example above).
> 
> analogous code but using 'dimnames<-' on a matrix performs a side effect
> on the matrix even if it initially does not have dimnames:
> 
>     x = matrix(1,1,1)
>     dimnames(x)
>     # NULL
>     'dimnames<-'(x, list('foo', 'bar'))
>     dimnames(x)
>     # list("foo", "bar")
> 
> this is incoherent with the first example above, in that in both cases
> the structure initially has no names or dimnames attribute, but the end
> result is different in the two examples.
> 
> is there something i misunderstand here?

Only the ideology/pragmatism... In principle, R has call-by-value
semantics and a function does not destructively modify its arguments(*),
and foo(x)<-bar behaves like x <- "foo<-"(x, bar). HOWEVER, this has
obvious performance repercussions (think x <- rnorm(1e7); x[1] <- 0), so
we do allow destructive modification by replacement functions, PROVIDED
that the x is not used by anything else. On the least suspicion that
something else is using the object, a copy of x is made before the
modification.

So

(A) you should not use code like y <- "foo<-"(x, bar)

because

(B) you cannot (easily) predict whether or not x will be modified
destructively

--------
(*) unless you mess with match.call() or substitute() and the like. But
that's a different story.


-- 
   O__  ---- Peter Dalgaard             ?ster Farimagsgade 5, Entr.B
  c/ /'_ --- Dept. of Biostatistics     PO Box 2099, 1014 Cph. K
 (*) \(*) -- University of Copenhagen   Denmark      Ph:  (+45) 35327918
~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk)              FAX: (+45) 35327907



[Rd] surprising behaviour of names<-
Peter Dalgaard