[R] source() vs attach()0

Duncan Murdoch murdoch at stats.uwo.ca
Wed Nov 11 16:39:04 CET 2009


On 11/11/2009 10:19 AM, Stefan Zeugner wrote:
> Duncan Murdoch wrote:
>> Just declaring it there is the only reasonable way, i.e.
>>
>> test<-function(foo) {
>>   subtest <- function() {
>>      foo <<- foo+1
>>   }
>>   subtest()
>>   return(foo)
>> }
>>
>> The reason you can't somehow assign it within an existing test is that 
>> subtest is a different closure every time.  Its environment will be 
>> the local frame of the call to test, so the "foo" on the right hand 
>> side of the assignment will be the value that was passed to test.
>>
>> An unreasonable way to get what you want is to mess with the 
>> environment, e.g.
>>
>> subtest <- function() {
>>    foo <<- foo+1
>> }
>>
>> test <- function(foo) {
>>    mysubtest <- subtest  # make a local copy
>>    environment(mysubtest) <- environment()  # attach the local frame
>>
>>    mysubtest()
>>    return(foo)
>> }
>>
>> This is ugly programming, likely to bite you at some future date.
>>
>> Duncan Murdoch
> 
> 
> Duncan,
> Thank you a lot for this clarification.
> Unfortunately, I have to get through this at the moment: I have 
> subfunctions that are to be used by in the environments of several 
> 'main' functions: and I prefer not to declare them separately each time.
> Therefore I will have to mess with the environment (for now) :-(
> 
> In this case, would it be wiser to shift the 'environment messing' to 
> the subfunction?
> I.e. tell it to manipulate its respective parent environment, as in the 
> example below?
> 
> subtest <- function() {
>  eval(expression(foo <- foo+1),parent.frame())
> }
> 
> test <- function(foo) {
>    subtest()
>    return(foo)
> }

I would say both are bad choices.  For both, if you later decide to 
change the name of the argument to test(), you break subtest().
For yours, suppose you want to change this later, and introduce an 
intermediary "mid()".  mid() is called by test(), and mid() calls 
subtest().  Then the foo in test won't get changed.

It's better to avoid non-standard evaluation.  Why not pass foo as an 
argument to subtest, and return it as the value?

That is,

subtest <- function(foo) {
   foo + 1
}

test <- function(foo) {
   foo <- subtest(foo)
   return(foo)
}

This will work, it's easy to modify to introduce an intermediary, it 
reduces the dependence between subtest and test, etc.

Duncan Murdoch




More information about the R-help mailing list