[R] Scoping rules

Prof Brian Ripley ripley at stats.ox.ac.uk
Thu Oct 9 08:45:03 CEST 2003


On Wed, 8 Oct 2003, Roger D. Peng wrote:

> I think I misinterpreted this section of the help file for get():
> 
>       If `inherits' is `FALSE', only the first frame of the specified
>       environment is inspected.  If `inherits' is `TRUE', the search is
>       continued up through the parent frames until a bound value of the
>       right mode is found.
> 
> Should this read "parent environments" instead of "parent frames"?  I'm 
> taking this from R 1.7.1.

It should read `enclosing' not `parent' for a start.

Thanks: we will try to get this consistent.

> 
> -roger
> 
> Prof Brian Ripley wrote:
> 
> > On Wed, 8 Oct 2003, Roger D. Peng wrote:
> > 
> > 
> >>It seems like you want in fnB
> >>
> >>get(AA$first, envir = parent.frame(1))
> >>
> >>but I'm entirely clear on why your original function doesn't work.  My 
> >>understanding was that get() should search through the parent frames.
> > 
> > 
> > Where did you get that idea from?  Argument `inherits' to get() defaults
> > to TRUE and is defined as
> > 
> > inherits: should the enclosing frames of the environment be inspected?
> > 
> > Note `enclosing', not `parent'.  So the normal R scope rules apply when
> > looking for an object from the frame of fnB, which as its environment (aka
> > enclosing frame) is the workspace (.GlobalEnv) is to look in the local
> > frame and then along the search path.
> > 
> > [This does seem a fairly common misconception, so if you do have any idea 
> > in which document it arises it would be good to know.]
> > 
> > 
> >>Peter Alspach wrote:
> >>
> >>>Dear List members:
> >>>
> >>>I'm using R1.7.1 (Windows 2000) and having difficulty with scoping. 
> >>>I've studied the FAQ and on-line manuals and think I have identified
> >>>the
> >>>source of my difficulty, but cannot work out the solution.
> >>>
> >>>For the purposes of illustration.  I have three functions as defined
> >>>below:
> >>>
> >>>fnA <- function(my.x)
> >>>{
> >>>  list(first=as.character(substitute(my.x)), second=sqrt(my.x))
> >>>}
> >>>
> >>>fnB <- function(AA)
> >>>{
> >>>  tmp.x <- get(AA$first)
> >>>  tmp.x^2
> >>>}
> >>>
> >>>fnC <- function()
> >>>{
> >>>  x <- 1:2
> >>>  y <- fnA(x)
> >>>  z <- fnB(y)
> >>>  c(x,y,z)
> >>>}
> >>>
> >>>fnA() has a vector as an argument and returns the name of the vector
> >>>and the square root of its elements in a list.  fn(B) takes the result
> >>>of fn(A) as its argument, gets the appropriate vector and computes the
> >>>square of its elements.  These work fine when called at the command
> >>>line.
> >>>
> >>>fnC() defines a local vector x and calls fnA() which operates on this
> >>>vector.  Then fnB() is called, but it operates on a global vector x in
> >>>GlobalEnv (or returns an error is x doesn't exist there) - but I want
> >>>it
> >>>to operate on the local vector.
> > 
> > 
> > I am not sure what you really want to do here, but R works best if you 
> > pass functions an object to work on, and not the name of an object.
> > Normally this sort of thing is best avoided, but if it is really needed it 
> > is normally simpler to find the object in the calling function (your fnC).
> > 
> > 
> >>>I think this is related to the enclosing environment of all three
> >>>functions being GlobalEnv (since they were created at the command
> >>>line),
> >>>but the parent environment of fnB() being different when invoked from
> >>>within fnC().
> >>>
> >>>My questions:
> >>>
> >>>1  Have I correctly understood the issue ?
> >>>2  How do I make fnB() operate on the local vector rather than the
> >>>global one ?
> >>>3  And, as an aside, I have used as.character(substitute(my.x)) to
> >>>pass
> >>>the name - but deparse(substitute(my.x)) also works.  Is there any
> >>>reason to prefer one over the other?
> > 
> > 
> > deparse() is preferred.  One subtle reason is what happens with very long 
> > expressions (and note deparse may give more than one line of output), 
> > but the main reason is what happens with expressions such as calls:
> > 
> > 
> >>fn1 <- function(x) as.character(substitute(x))
> >>fn2 <- function(x) deparse(substitute(x))
> >>fn1(log(x))
> > 
> > [1] "log" "x"  
> > 
> >>fn2(log(x))
> > 
> > [1] "log(x)"
> > 
> > 
> > It is normally dangerous to use get() on the result of 
> > deparse(substitute()), as the latter may be the character representation 
> > of an expression and not a simple name.
> > 
> 
> 

-- 
Brian D. Ripley,                  ripley at stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595




More information about the R-help mailing list