5

Programmers often uses multiple small functions inside of larger functions. Along the way we may want to collect things in an environment for later reference. We could create an environment with new.env(hash=FALSE) and pass that along to the smaller functions and assign with assign. Well and dandy. I was wondering if we could use the reference id of the environment and not pass it along to the child functions but still assign to the environment by reference the environment id.

So here I make

myenv <- new.env(hash=FALSE)
## <environment: 0x00000000588cc918>

And as typical could assign like this if I passed along to the child functions the environment.

assign("elem1", 35, myenv)

myenv[["elem1"]]
# 35

What I want is to make the environment in the parent function and pass the reference id along instead so I want to do something like:

assign("elem2", 123, "0x00000000588cc918")

But predictably results in:

## Error in as.environment(pos) : 
##   no item called "0x00000000588cc918" on the search list

Is it possible to pass along just the environment id and use that instead? This seems cleaner than passing the environment from function to function and returning as a list and then operating on the environment in that list...and maybe more memory efficient too.

I would want to also access this environment by reference as well.

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
  • 1
    @G.Grothendieck Thank you, good information. The main motivation is that it's easier to pass the character reference id from function to function and modify in place. Then we don't have to return the environment each time from the child functions. – Tyler Rinker Oct 16 '15 at 13:47
  • 1
    @TylerRinker “it is easier” — come again?! No, it’s much more complex. I mean, there isn’t even an easy way to get this internal hex identifier for an environment (you’d essentially need to do `capture.output(print(myenv))` and then parse the result of that. In fact, forget about the hex identifier. It’s just part of the pretty printing to make environments uniquely identifiable. Beyond that, it has no meaning (to the R programmer). – Konrad Rudolph Oct 16 '15 at 14:36
  • I was under the impression that the "unique identifier" / "environment id" is just the memory address of the object, no? E.g., `E <- new.env(); sub(".+\\s(.+?)>$", "\\1", capture.output(print(E))) == data.table::address(E)`. But regardless, seeing as R doesn't directly provide a means of accessing environments in this manner (that I'm aware of), trying to do so is probably more trouble than it's worth. – nrussell Oct 16 '15 at 14:44
  • @KonradRudolph This means I take your word for it. I asked because I believe there is a way. How else do things like data.table alter in memory? It must be possible. – Tyler Rinker Oct 16 '15 at 14:57
  • @TylerRinker I don’t know how exactly data.table operates but fundamentally you can of course do all these things in C or C++ using the internal R API. However, in R code (“userland”, if you will), there’s no need to glimpse under the hood for operations R supports well on its own. – Konrad Rudolph Oct 16 '15 at 15:07
  • @G.Grothendieck perfect can you add as an answer? – Tyler Rinker Oct 17 '15 at 02:06

1 Answers1

3

Environments are not like lists. Passing an environment to a function does not copy its contents even if the contents of the environment are modified within the function so you don't have to worry about inefficiency. Also, when an environment is passed to a function which modifies its contents the contents are preserved even after the function completes so unlike the situation with lists there is no need to pass the environment back.

For example, the code below passes environment e to function f and f modifies the contents of it but does not pass it back. After f completes the caller sees the change.

    f <- function(x, env) { 
       env$X <- x
       TRUE 
    }

    e <- new.env()
    f(1, e)
    ## [1] TRUE

    e$X
    ## [1] 1

More about enviorments in Hadely's book: http://adv-r.had.co.nz/Environments.html

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341