Environments
Table of Contents
- Advanced R: Environments
search()
new.env(parent = parent.frame())
ls(name, all.names = FALSE)
ls.str(name, all.names = FALSE)
parent.env()
vsparent.frame()
with(data, expr, ...)
within(data, expr, ...)
Advanced R: Environments tutorial
Basics
- Every environment except the empty environment, the ultimate ancestor of all environments, has a parent.
- If a name is not found in an environment, then R will look in its parent (and so on).
globalenv()
- the environment in which you normally work.
baseenv()
- the environment of the
base
package. Its parent is theempty
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
- The environment where the function was created.

globalenv()
is both the enclosing and the binding environment.Binding environments

globalenv()
is the enclosing, e
is the bindingPackage 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:

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
- Every time a function is called, a new environment is created to host execution.
- The parent of the execution environment is the enclosing environment of the function.
- Once the function has completed, this environment is thrown away.
When you create a function inside another function,
- The enclosing environment of the child function is the execution environment of the parent
- which means the execution environment is no longer ephemeral.
Calling environments
- R’s regular scoping rules only use the enclosing parent
parent.frame()
allows you to access the calling parent.
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
- Names usually consist of letters, digits,
.
and_
, and can’t begin with_
. - There are two other special types of binding, delayed and active:
<-
creates a variable in the current environment.<<-
modifies an existing variable found by walking up the parent environments. if not found any, creates a variable inglobalenv
.- A delayed binding creates and stores a promise to evaluate the expression when needed.
- We can create delayed bindings with the special assignment operator
%<d-%
, provided by thepryr
package. - Active are not bound to a constant object. Instead, they’re re-computed every time they’re accessed
- To create active binding, use
%<a-$
.
user system elapsed
0 0 0
user system elapsed
0 0 1
user system elapsed
0 0 0
[1] 0.1530638
[1] 0.4654055
Explicit environments
- Unlike most objects in R, when you modify an environment, it does not make a copy.
- Since environments have reference semantics, you’ll never accidentally create a copy. This makes it a useful vessel for large objects.
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.
[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
[1] "x" "y"
[1] ".hidden" "x" "y"
ls.str(name, all.names = FALSE)
reference
Show str()
of all names from ls()
x : num 10
y : num 20
parent.env()
vs parent.frame()
discussion
parent.env()
returns the enclosing environmentparent.frame()
returns the calling environment
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.
x : num 10
$x
[1] 20