[R] Scoping rules
Roger D. Peng
rpeng at jhsph.edu
Thu Oct 9 04:38:50 CEST 2003
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.
-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.
>
More information about the R-help
mailing list