Environments

Table of Contents

Advanced R: Environments tutorial

Basics

globalenv()
the environment in which you normally work.
baseenv()
the environment of the base package. Its parent is the empty environment.
emptyenv()
is the ultimate ancestor of all environments
Simple operations related to environments
<environment: R_GlobalEnv>
[1] "a" "b" "c"
<environment: 0x7fd053291808> 
a :  num 1
b :  num 2
c :  num 3
[1] 3
[1] "b" "c"
[1] FALSE
[1] TRUE
[1] TRUE

Function environments

There are different kinds of environments related to functions

binding environment
binding a function to a name with <- defines a binding environment
execution environment
calling a function creates an ephemeral execution environment that stores variables created during execution
calling environment
Every execution environment is associated with a calling environment, which tells you where the function was called

The enclosing environment

y <- 1
f <- function(x) x + y
In this case, globalenv() is both the enclosing and the binding environment.
In this case, globalenv() is both the enclosing and the binding environment.

Binding environments

e <- new.env()
e$g <- function() 1
globalenv() is the enclosing, e is the binding
globalenv() is the enclosing, e is the binding

Package Namespaces

This works because every package has two environments associated with it: the package environment and the namespace environment.

package environment
every publicly accessible function, and is placed on the search path.
namespace environment
contains all functions (including internal functions), and its parent environment is a special imports environment that contains bindings to all the functions that the package needs.

Every exported function in a package is bound into the package environment, but enclosed by the namespace environment. This complicated relationship is illustrated by the following diagram:

When we type var (green) into the console, it's found first in the global environment(which is one of binding environments). When sd() looks for var() it finds it first in its namespace environment so never looks in the globalenv().
When we type var (green) into the console, it's found first in the global environment(which is one of binding environments). When sd() looks for var() it finds it first in its namespace environment so never looks in the globalenv().

Execution environments

When you create a function inside another function,

Calling environments

x <- 20
f <- function() {
  x <- 10
  def <- get("x", environment())
  cll <- get("x", parent.frame())
  print(def)
  print(cll)
}
f()
[1] 10
[1] 20

Biding names to values

library(pryr)
system.time(b %<d-% {Sys.sleep(1); 1})
system.time(b)
system.time(b)
   user  system elapsed 
      0       0       0 
   user  system elapsed 
      0       0       1 
   user  system elapsed 
      0       0       0 
library(pryr)
x %<a-% runif(1)
x
x
[1] 0.1530638
[1] 0.4654055

Explicit environments

modify <- function(x) {
  x$a <- 2
  invisible()
}
the original list is not changed because modifying a list actually creates and modifies a copy.
[1] 1
However, if you apply it to an environment, the original environment is modified:
[1] 2

search() reference

search() lists all parents of the global environment.

search()
[1] ".GlobalEnv"        "package:stats"     "package:graphics" 
[4] "package:grDevices" "package:utils"     "package:datasets" 
[7] "package:methods"   "Autoloads"         "package:base"     

new.env(parent = parent.frame()) reference

e <- new.env()
# The default parent provided by new.env() is environment from
# which it is called - in this case that's the global environment.
# This is because R evaluates function arguments lazily.
parent.env(e)
<environment: R_GlobalEnv>

ls(name, all.names = FALSE) reference

name
this accepts an environment object
all.names
If FALSE, names which begin with a . are omitted
x = 10
y = 20
.hidden = 30
ls(environment())
ls(environment(), all.names = TRUE)
[1] "x" "y"
[1] ".hidden" "x"       "y"      

ls.str(name, all.names = FALSE) reference

Show str() of all names from ls()

x = 10
y = 20
ls.str(environment())
x :  num 10
y :  num 20

parent.env() vs parent.frame() discussion

name <- "global"
f <- function() {
  name <- "f"
  g <- function() {
    e <- environment()
    list(parent.env = get("name", parent.env(e)),
         parent.frame = get("name", parent.frame()))
  }
}
g <- f()
g()
$parent.env
[1] "f"

$parent.frame
[1] "global"

with(data, expr, ...) reference

within(data, expr, ...) reference

data
data to use for constructing an environment, may be an environment, a list, a data frame, etc.
expr
expression to evaluate

Unlike with(), within() makes a modified copy of data. with() returns the evaluated expr, while within() returns the modified copy.

e <- new.env()
with(e, x <- 10)
ls.str(e)
x :  num 10
l <- list()
within(l, x <- 20)
$x
[1] 20