[R] 'with' usage question

Thomas Lumley tlumley at u.washington.edu
Thu Oct 7 22:06:39 CEST 2004

On Thu, 7 Oct 2004, RenE J.V. Bertin wrote:

> On Thu, 07 Oct 2004 13:17:02 -0400, "Roger D. Peng" <rpeng at jhsph.edu> wrote regarding "Re: [R]
> 'with' usage question"
> 8-) I think what's happening is that the function aov.SS1 will look up
> 8-) variables in the environment in which it was *defined*, which in your
> 8-) case (I'm guessing) is the global environment/workspace.  Therefore,
> 8-) if `speed' and `Subject' are not defined in the global environment,
> 8-) they will not be found.
> If you take that to the letter, doesn't it mean that attach() and 
> detach() couldn't have the effect they have? Which is, in fact and if 
> memory serves me well, much like the Pascal 'with' operator.

No. attach() attaches the data frame to the search path after the global 
environment. So variables in an attached data frame are always available 
(but may be overridden by variables in the global environment).  attach() 
is superficially like with(), but not exactly the same. If you define

    with_attach <-function(data, expr){
 			eval(substitute(expr), parent.frame())

it would behave more as you expected in this case.  Inside a function this 
is not as good as with() because variables in the data frame can be 
overriden by local variables.

>								A 
> (possible) counter argument: aov.SS1() used T and F as the usual 
> abbreviations for TRUE and FALSE: these are defined in the global 
> environment. Now my dataframes also contain a variable T: it took me 
> quite a while to realise that this variable (which I in fact never use 
> directly) would override the T constant/operator and cause hard-to-trace 
> error messages.

and that's why R CMD check tells you not to use T/F for TRUE/FALSE

> I'm trying to find some analogy. with() extends the current environment 
> with the variables in the given dataframe, but does not create a C-like 
> scope. Rather, it functions more or less like a Bourne shell script: the 
> new variables are not 'exported' to be available to code evoked from 
> within that new environment, unless they were specifically passed as 
> arguments.

It does create a new scope, as in C. The variables are not available 
inside functions called from that scope, because variables are never 
exported to functions called from a given scope. The same is true in C: 
variables will not be exported to functions *called from* a given block 
unless they are explicitly passed as arguments.

The reason many people expect variables to be available in functions 
called from a given scope ("dynamic scoping") is that variables in the 
global workspace are available in functions called from the global 
workspace. But this is just a coincidence: the variables are available 
because the function is *defined* in the global workspace (or in an 
environment that includes the global workspace).  Where it is called from 
is irrelevant.

It is also initially confusing that having a default argument value is 
different from giving exactly the same expression as the actual argument 
value.  This is also for a good reason: it is important for default 
arguments to be able to depend on other argument values. This means they 
have to be evaluated in an environment where the other formal arguments 
are available -- inside the function

So in your example
   with( data, aov.SS1( y=Obs, indep=speed, fSnr=Subject ) )
works, because actual arguments are evaluated in the calling environment, 
which is inside with(), where speed and Subject are available.
    with( data, aov.SS1( y=Obs))
doesn't work because indep=speed and fSnr=Subject are evaluated inside 
aov.SS1, where speed and Subject aren't available.

>		Which still doesn't explain why ls() sees everything when 
> called within a with() statement...

Yes, it does.  If ls() is used inside with() it sees the scope defined by 
with(), but if it is called inside a function called from with() it sees 
the environment inside that function: eg

> with(trees, ls())
[1] "Girth"  "Height" "Volume"
> f<-function() ls()
> with(trees, f())


More information about the R-help mailing list