[R] with vs. attach

Spencer Graves spencer.graves at effectivedefense.org
Fri May 6 14:47:18 CEST 2016



On 5/6/2016 6:46 AM, peter dalgaard wrote:
> On 06 May 2016, at 02:43 , David Winsemius <dwinsemius at comcast.net> wrote:
>
>>> On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
>>>
>>> I want a function to evaluate one argument
>>> in the environment of a data.frame supplied
>>> as another argument.  "attach" works for
>>> this, but "with" does not.  Is there a way
>>> to make "with" work?  I'd rather not attach
>>> the data.frame.
>>>
>>>
>>> With the following two functions "eval.w.attach"
>>> works but "eval.w.with" fails:
>>>
>>>
>>> dat <- data.frame(a=1:2)
>>> eval.w.attach <- function(x, dat){
>>>   attach(dat)
>>>   X <- x
>>>   detach()
>>>   X
>>> }
>>>
>>> eval.w.with <- function(x, dat){
>>>   with(dat, x)
>>> }
>>>
>>> eval.w.attach(a/2, dat) # returns c(.5, 1)
>> How about using eval( substitute( ...))?
>>
>> eval.w.sub <- function(expr, datt){
>>    eval( substitute(expr), env=datt)
>>                          }
>> eval.w.sub(a/2, dat)
>> #[1] 0.5 1.0
>>
>>
> Actually, I think a better overall strategy is to say that if you want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object).
>
> Once you figure out _how_ your eval.w.attach works (sort of), you'll get the creeps:
>
> Lazy evaluation causes the argument x to be evaluated after the attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function.
>
> Apart from upsetting computer science purists, there could be hidden problems: One major issue is that  values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic.
>
> So my preferences go along these lines:
>
>> dat <- data.frame(a=1:2)
>> eval.expression <- function(e, dat) eval(e, dat)
>> eval.expression(quote(a/2), dat)
> [1] 0.5 1.0
>> eval.expression(expression(a/2), dat)
> [1] 0.5 1.0
>
>> eval.formula <- function(f, dat) eval(f[[2]], dat)
>> eval.formula(~a/2, dat)
> [1] 0.5 1.0

Hi, Peter:


       I don't like eval.expression or eval.formula, because they don't 
automatically accept what I naively thought should work and require more 
knowledge of the user.  What about David's eval.w.sub:


a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
   eval( substitute(a), env=Dat)
}
 > eval.w.sub(a/2, dat)
[1] 0.5 1.0


       This produces what's desired in a way that seems simpler to me.


       By the way, I really appreciate Peter's insightful comments:


eval.w.attachOops <- function(x, Dat){
   attach(Dat)
   X <- x
   detach()
   X
}
 > eval.w.attachOops(a/2, dat)
The following object is masked _by_ .GlobalEnv:

     a

[1] 1.570796
 > eval.w.attachOops(b/2, dat)
The following object is masked _by_ .GlobalEnv:

     a

Error in eval.w.attachOops(b/2, dat) : object 'b' not found
 > search()
[1] ".GlobalEnv"        "Dat"               "package:graphics"
[4] "package:grDevices" "package:utils"     "package:datasets"
[7] "package:methods"   "Autoloads"         "package:base"
 > objects(2)
[1] "a"

*** NOTES:


       1.  This gives a likely wrong answer with a warning if "a" exists 
in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.



       2.  A stray "detach()" [not shown here] detached 
"package:stats".  oops.


*** Using "on.exit" fixes the problem with failure to detach but not the 
likely wrong answer:


detach()
search()
eval.w.attachStillWrong <- function(x, dat){
   attach(dat)
   on.exit(detach(dat))
   X <- x
   X
}
The following object is masked _by_ .GlobalEnv:

     a

[1] 1.570796
 > eval.w.attachStillWrong(b/2, dat)
The following object is masked _by_ .GlobalEnv:

     a

Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
 > search()
[1] ".GlobalEnv"        "package:grDevices" "package:utils"
[4] "package:datasets"  "package:methods"   "Autoloads"
[7] "package:base"


       Thanks again to Peter and David.  Spencer

> Peter D.
>
>
>
>> -- 
>> David.
>>
>>
>>> eval.w.with(a/2, dat) # Error ... 'a' not found
>>>
>>>
>>> Thanks, Spencer Graves
>>>
>>> 	[[alternative HTML version deleted]]
>>>
>>> ______________________________________________
>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>>> 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.
>> David Winsemius
>> Alameda, CA, USA
>>
>> ______________________________________________
>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>> 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