Search code examples
rgeneratorlocalenvironment

How does an environment remember that it exists?


Take

adder <- local({
x <- 0
function() {x <<- x+1; x}
})

or equivalently

adderGen <- function(){
x <- 0
function() {x <<- x+1; x}
}
adder<-adderGen()

Calling adder() will return 1 calling it again returns 2, and so on. But how does adder keep count of this? I can't see any variables hitting the global environment, so what is actually being used to store these? Particularly in the second case, you'd expect adder to forget that it was made inside of a function call.


Solution

  • To see what is happening, let us define the function as follows:

    adderGen <- function(){
      print("Initialize")
      x <- 0
      function() {x <<- x+1; x}
    }
    

    When we evaluate it, we obtain:

    adder <- adderGen()
    # [1] "Initialize"
    

    The object that has been assigned to adder is the inside function of adderGen (which is the output of adderGen). Note that, adder does not print "Initialize" any more.

    adderGen
    # function(){
    #   print("Initialize")
    #   x <- 0
    #   a <- function() {x <<- x+1; x}
    # }
    adder
    # function() {x <<- x+1; x}
    # <environment: 0x55cd4ebd3390>
    

    We can see that it also creates a new calling environment, which inherits the variable x in the environment of adderGen.

    ls(environment(adder))
    # [1] "x"
    get("x",environment(adder))
    # [1] 0
    

    The first time adder is executed, it uses the inherited value of x, i.e. 0, to redefine x as a global variable (in its calling environment). And this global variable is the one that it is used in the next executions. Since x <-0 is not part of the function adder, when adder is executed, the variable x is not initialized to 0 and it increments by one the current value of x.

    adder()
    # [1] 1