Environments formalize relationships between variable names and values.
When you enter x <- 55 into the R console what you’re saying is: assign the value of 55 to a variable called x, and store this assignment in the global environment. The global environment is therefore where most R users do most of their programming and analysis.
new.env()my_new_env <- new.env()
Like a list:
my_new_env$x <- 4
my_new_env$x
## [1] 4
With assign() and get():
assign("y", 9, envir = my_new_env)
get("y", envir = my_new_env)
## [1] 9
ls() and exists()ls(my_new_env)
## [1] "x" "y"
ls.str(my_new_env)
## x : num 4
## y : num 9
exists("x", envir = my_new_env)
## [1] TRUE
exists("z", envir = my_new_env)
## [1] FALSE
rm()rm(y, envir = my_new_env)
exists("y", envir = my_new_env)
## [1] FALSE
my_new_env$y
## NULL
Environments are organized in parent/child relationships such that every environment keeps track of its parent, but parents are unaware of which environments are their children.
You can see the parents of the global environment using the search() function:
search()
## [1] ".GlobalEnv" "package:stats" "package:graphics"
## [4] "package:grDevices" "package:utils" "package:datasets"
## [7] ".env" "package:methods" "Autoloads"
## [10] "package:base"
As you can see package:stats is the parent of .GlobalEnv, and package:graphics is parent of package:stats, and so on. In general the parent of .GlobalEnv is always the last package that was loaded using library().
Notice that after we load the ggplot2 package, that package becomes the parent of .GlobalEnv:
library(ggplot2)
search()
## [1] ".GlobalEnv" "package:ggplot2" "package:stats"
## [4] "package:graphics" "package:grDevices" "package:utils"
## [7] "package:datasets" ".env" "package:methods"
## [10] "Autoloads" "package:base"
Although there may be several cases where you need to create a new environment using new.env(), you will more often create new environments whenever you execute functions. An execution environment is an environment that exists temporarily within the scope of a function that is being executed.
x <- 10
my_func <- function(){
x <- 5
return(x)
}
my_func()
## [1] 5
First the name x is bring assigned the value 10 in the global environment.
Then the name my_func is being assigned the value of the function function(){x <- 5};return(x)} in the global environment.
When my_func() is executed, a new environment, the execution environment, is created as a child of the global environment.
This execution environment only exists while my_func() is running.
Inside of the execution environment the name x is assigned the value 5.
When return() is executed it looks first in the execution environment for a value that is assigned to x. Then the value 5 is returned.
In contrast to the situation above, take a look at this variation:
x <- 10
another_func <- function(){
return(x)
}
another_func()
## [1] 10
In this situation the execution environment inside of another_func() does not contain an assignment for the name x, so R looks for an assignment in the parent environment of the execution environment which is the global environment. Since x is assigned the value 10 in the global environment 10 is returned.
<<-The complex assignment operator can be used to re-assign or even create name-value bindings in the parent environment (e.g., the global environment) from within a child environment (e.g., an execution environment).
x <- 10
x
## [1] 10
Re-assign:
assign1 <- function(){
x <<- "Wow!"
}
assign1()
x
## [1] "Wow!"
Create:
a_variable_name
Error in eval(expr, envir, enclos): object ‘a_variable_name’ not found
exists("a_variable_name")
## [1] FALSE
assign2 <- function(){
a_variable_name <<- "Magic!"
}
assign2()
exists("a_variable_name")
## [1] TRUE
a_variable_name
## [1] "Magic!"
Environments can be thought of as consisting of two things:
When R looks up the value for a symbol the frame is examined and if a matching symbol is found its value will be returned. If not, the enclosing environment is then accessed and the process repeated.
Environments form a tree structure in which the enclosures play the role of parents. The tree of environments is rooted in an empty environment, available through emptyenv(), which has no parent.
It is possible for an environment to have multiple “children”. The only environment without a parent is the empty environment.
The most common example is the frame of variables local to a function call; its enclosure is the environment where the function was defined.
The enclosing environment or enclosure or parent environment is distinguished from the parent frame: the latter refers to the environment of the caller of a function.
r_envirs <- function(ini_env) {
print(environmentName(ini_env))
parent_env <- parent.env(ini_env)
if (environmentName(parent_env) != environmentName(emptyenv())) {
r_envirs(parent_env)
}
}
r_envirs(globalenv())
## [1] "R_GlobalEnv"
## [1] "package:ggplot2"
## [1] "package:stats"
## [1] "package:graphics"
## [1] "package:grDevices"
## [1] "package:utils"
## [1] "package:datasets"
## [1] ".env"
## [1] "package:methods"
## [1] "Autoloads"
## [1] "base"
Environments are created implicitly by function calls. In this case the environment contains the variables local to the function (including the arguments), and its enclosure is the environment of the currently called function. Environments may also be created directly by new.env.
When get or exists search an environment with the default inherits = TRUE, they look for the variable in the frame, then in the enclosing frame, and so on.
The global environment .GlobalEnv, more often known as the user’s workspace, is the first item on the search path. It can also be accessed by globalenv(). On the search path, each item’s enclosure is the next item.
The object .BaseNamespaceEnv is the namespace environment for the base package. The environment of the base package itself is available as baseenv().
If one follows the chain of enclosures found by repeatedly calling parent.env from any environment, eventually one reaches the empty environment emptyenv(), into which nothing may be assigned.
The replacement function parent.env<- is extremely dangerous as it can be used to destructively change environments in ways that violate assumptions made by the internal C code. It may be removed in the near future.
System environments, such as the base, global and empty environments, have names as do the package and namespace environments and those generated by attach(). Other environments can be named by giving a “name” attribute, but this needs to be done with care as environments have unusual copying semantics.
If fun is a function or a formula then environment(fun) returns the environment associated with that function or formula. If fun is NULL then the current evaluation environment is returned.
The replacement form sets the environment of the function or formula fun to the value given.
is.environment(obj) returns TRUE if and only if obj is an environment.
new.env returns a new (empty) environment with (by default) enclosure the parent frame.
parent.env returns the enclosing environment of its argument.
parent.env<- sets the enclosing environment of its first argument.
environmentName returns a character string, that given when the environment is printed or “” if it is not a named environment.
env.profile returns a list with the following components: size the number of chains that can be stored in the hash table, nchains the number of non-empty chains in the table (as reported by HASHPRI), and counts an integer vector giving the length of each chain (zero for empty chains). This function is intended to assess the performance of hashed environments. When env is a non-hashed environment, NULL is returned.