ruedi ruedi - 3 months ago 16
R Question

Understanding Enclosing Environment

I have the following code

new_counter <- function(){
ij <- 0
function(){
ij <<- ij+1
ij
}
}

counter_one <- new_counter()
counter_two <- new_counter()

counter_one()
counter_one()


from this tutorial.

They write:


The counters get around the “fresh start” limitation by not modifying
variables in their local environment. Since the changes are made in
the unchanging parent (or enclosing) environment, they are preserved
across function calls.


This is what I think is going on: The
new_counter
function is created in the
.GlobalEnv
(
enclosing environment
) as well as the
counter_one
function. But the
execution environment
of
new_counter
function is one level higher than the counter_one functions. This is usually temporary but this time it is not since we have an enclosure function.

But how can I see 'this' enclosing enviroment and that they are one level apart? Using (pryr)
where
and environment delivers for both functions the global environment.

EDIT:
They talk about two different environments:


  1. 'in theire local environment'

  2. 'in the unchainging parent environment'



So to me these are two different environments but if they differ they probably have a different name! How can I find out the name? Using

where("new_counter")
where("counter_one")


both deliver the global environment but looking in the enumeration above this must be two different ones.

Answer

This should hopefully clarify what is happening. Note that the enclosing environment of new_counter is the global environment but the environments of counhter_one and counter_two are the environments within the two execution instances of new_counter. Normally a function's enclosing environment is its lexical environment (the environment where it is defined) but in some situations this varies.

new_counter <- function(){
  e <- environment()
  print(e)
  ij <- 0
  function(){
    ij <<- ij+1
    ij
  }
}

counter_one <- new_counter()  # A
counter_two <- new_counter()  # B

counter_one()
counter_one()

environment(new_counter) # global environment

environment(counter_one) # see output of A
environment(counter_two) # see output of B

Here is a simpler example that shows that a function can be located in one environment yet its enclosing environment can be a different environment. In this case f is in the global environment; however, its enclosing environment is e and not the global environment.

e <- new.env()
e$x <- 1
x <- 2
f <- function() x
environment(f) <- e
f() 
## [1] 1

There is some discussion here: http://adv-r.had.co.nz/Environments.html

Comments