Skip to content

function changes argument (PR#9216)

3 messages · Brian Ripley, Peter Dalgaard

#
I can tell you where the problem is and a workaround:

f <- function(LL) for (ll in names(LL)) LL[[ll]]$txt<-"changed in f"

works.  The problem is that for() is directly exposing the elements of a 
list.

Of course, a more idiomatic construction would be

LL <- lapply(LL, function(x) x$txt <- "changed in f")

which also works.

The question is whether we do wish to change this to make the construction 
work as Andreas appears to intend.  The simplest solution is a 
precautionary duplicate in for(), which is potentially very expensive and 
almost always unneeded.

However, we already have

x <- 1:10
for(i in x) i <- pi
x

which does not change x, so I think the right solution is to make the list 
(LL here) read-only, which can be done cheaply.  That is also AFAICS what 
S does.
On Mon, 11 Sep 2006, murdoch at stats.uwo.ca wrote:

            

  
    
#
ripley at stats.ox.ac.uk writes:
We could have a precautionary (virtual) assignment, effectively

for (`*tmp*` in L) { ll <- `*tmp*` ; .......}

I think this is what is supposed to happen in the R semantics, it also
satisfies the convention that ll is defined at the end of the loop as
the last value obtained. Assigning to the loop variable should not
change the structure from which it comes, even if Andreas intended
otherwise.

It's not the same as duplicating: it may change NAMED on the elements
of L and cause extra duplication down the line, but not invariably so.

I suspect that the only reason it isn't what currently happens is
that we have forgotten to diddle the NAMED flag in the implementation
of for(), in the same way as is done for "<-".
#
On Mon, 11 Sep 2006, Peter Dalgaard wrote:

            
Yes, on the list elements if the list is itself named, which I have 
already implemented. (I also added a shallow copy, which is needed if L is 
not to be read-only, but that seems not the closest analogy in 
retrospect.)