简体   繁体   中英

Is in case of R functions a parent's parent environment of an environment also parent to the environment?

Assume, I create a parent's parent environment (E2 <= environment E1 <= environmet E) of an environment (E). My questions is, whether E2 is also parent to E. To me it was clear, that the answer was yes, but the following code seems to state the opposite.

What is wrong? See the last line in the reproducible example below, where print(parent-parent ) yields

# [1] FALSE # I would expect a TRUE here!!

From the docs ?parent.env

If one follows the chain of enclosures found by repeatedly calling parent.env from any environment, eventually one reaches the empty environment emptyenv(), into which nothing may be assigned.

subfun0 <- function() {
  e <- parent.frame()
  attr(e, "name") <- "my_env"
  assign("my_env", 1,
         envir = parent.frame(),
         inherits = FALSE, immediate = TRUE)
  return(NULL)
}

subsubfun <- function() {
  print("  subsubfun")
  print("  =========")
  print(exists("my_env"))
  print(exists("my_env", parent.frame()))
  env <- parent.frame()
  print(exists("my_env", parent.env(env)))
  # print(parent.env(env)) # <environment: R_GlobalEnv>??
  return(NULL)
}

subfun <- function() {
  print(" subfun")
  print(" ======")
  print(exists("my_env"))
  print(exists("my_env", parent.frame()))
  env <- parent.frame()
  print(exists("my_env", parent.env(env)))
  subsubfun()
  return(NULL)
}

fun1 <- function() {
  print("fun1")
  print("====")
  subfun0()
  print(exists("my_env"))
  print(exists("my_env", parent.frame()))
  env <- parent.frame()
  print(exists("my_env", parent.env(env)))
  subfun()
  return(NULL)
} 


fun1()
# [1] "fun1"
# [1] "===="
# [1] TRUE #     OK
# [1] FALSE
# [1] FALSE
# [1] " subfun"
# [1] " ======"
# [1] FALSE
# [1] TRUE #     OK
# [1] FALSE
# [1] "  subsubfun"
# [1] "  ========="
# [1] FALSE
# [1] FALSE
# [1] FALSE #    I would expect a TRUE here!!

The problem is that you are actually defining all your functions in the global environment, therefore their parent is the global environment.

You get what you would expect if you define your functions inside other functions. Look at the example below.

(Also I created a function that prints all parent environments till the global environment)

env_genealogy <- function(env){
    
    while(!identical(env, globalenv())){
        
        env <- parent.env(env)
        print(env)
        
    }
    
}



fun1 <- function() {
    subfun0 <- function() {
        
        print(" subfun0")
        print(" ======")
        
        env_genealogy(environment())
        
        e <- parent.frame()
        attr(e, "name") <- "my_env"
        assign("my_env", 1,
                     envir = parent.frame(),
                     inherits = FALSE, immediate = TRUE)
        return(NULL)
    }
    
    
    subfun <- function() {
        
        subsubfun <- function() {
            print("  subsubfun")
            print("  =========")
            
            env_genealogy(environment())
            
            print(exists("my_env"))
            print(exists("my_env", parent.frame()))
            env <- parent.frame()
            print(exists("my_env", parent.env(env)))
            # print(parent.env(env)) # <environment: R_GlobalEnv>??
            return(NULL)
        }
        
        print(" subfun")
        print(" ======")
        
        env_genealogy(environment())
        
        print(exists("my_env"))
        print(exists("my_env", parent.frame()))
        env <- parent.frame()
        print(exists("my_env", parent.env(env)))
        subsubfun()
        return(NULL)
    }
    
    
    
    print("fun1")
    print("====")
    
    env_genealogy(environment())
    
    subfun0()
    print(exists("my_env"))
    print(exists("my_env", parent.frame()))
    env <- parent.frame()
    print(exists("my_env", parent.env(env)))
    subfun()
    return(NULL)
} 


fun1()
[1] "fun1"
[1] "===="
<environment: R_GlobalEnv>
[1] " subfun0"
[1] " ======"
<environment: 0x000001b0e4b124d8>
<environment: R_GlobalEnv>
[1] TRUE
[1] FALSE
[1] FALSE
[1] " subfun"
[1] " ======"
<environment: 0x000001b0e4b124d8>
attr(,"name")
[1] "my_env"
<environment: R_GlobalEnv>
[1] TRUE
[1] TRUE
[1] FALSE
[1] "  subsubfun"
[1] "  ========="
<environment: 0x000001b0e552add0>
<environment: 0x000001b0e4b124d8>
attr(,"name")
[1] "my_env"
<environment: R_GlobalEnv>
[1] TRUE
[1] TRUE
[1] TRUE
NULL

For more details, have a look here


For a minimal example, you can look at this:

a <- function(){
    
    i
    
}
 
a()
> #> Error in a() : object "i" not found

b <- function(){
    
    i <- 1
    
    a()
    
}
b()
> #> Error in a() : object "i" not found
 
d <- function(){
    
    i <<- 1
    a()
    
}
d()
#> [1] 1
rm(i)
 
 
f <- function(){
    
    g <- a
    i <- 2
    g()
    
}
f()
#> Error in g() : object "i" not found

h <- function(){
    
    l <- function() i
    i <- 2
    l()
    
}
h()
#> [1] 2

When you call a() you get an error because i was not defined.

Even if you define i inside b() you get the same error because b 's environment is not shared with a . This is your case.

d() works because we assign i to the global environment with <<- .

f() doesn't work: even if we defined g inside f , we made a copy of a which copied also its parent environment.

We get a result in h() because l() was defined inside. This is the case I showed you in my answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM