These functions create new environments.

  • env() creates a child of the current environment by default and takes a variable number of named objects to populate it.

  • new_environment() creates a child of the empty environment by default and takes a named list of objects to populate it.

env(...)

child_env(.parent, ...)

new_environment(data = list(), parent = empty_env())

Arguments

..., data

Named values. You can supply one unnamed to specify a custom parent, otherwise it defaults to the current environment. These dots support tidy dots features.

.parent, parent

A parent environment. Can be an object supported by as_environment().

Environments as objects

Environments are containers of uniquely named objects. Their most common use is to provide a scope for the evaluation of R expressions. Not all languages have first class environments, i.e. can manipulate scope as regular objects. Reification of scope is one of the most powerful features of R as it allows you to change what objects a function or expression sees when it is evaluated.

Environments also constitute a data structure in their own right. They are a collection of uniquely named objects, subsettable by name and modifiable by reference. This latter property (see section on reference semantics) is especially useful for creating mutable OO systems (cf the R6 package and the ggproto system for extending ggplot2).

Inheritance

All R environments (except the empty environment) are defined with a parent environment. An environment and its grandparents thus form a linear hierarchy that is the basis for lexical scoping in R. When R evaluates an expression, it looks up symbols in a given environment. If it cannot find these symbols there, it keeps looking them up in parent environments. This way, objects defined in child environments have precedence over objects defined in parent environments.

The ability of overriding specific definitions is used in the tidyeval framework to create powerful domain-specific grammars. A common use of masking is to put data frame columns in scope. See for example as_data_mask().

Reference semantics

Unlike regular objects such as vectors, environments are an uncopyable object type. This means that if you have multiple references to a given environment (by assigning the environment to another symbol with <- or passing the environment as argument to a function), modifying the bindings of one of those references changes all other references as well.

Life cycle

  • child_env() is in the questioning stage. It is redundant now that env() accepts parent environments.

See also

Examples

# env() creates a new environment which has the current environment # as parent env <- env(a = 1, b = "foo") env$b
#> [1] "foo"
#> [1] TRUE
# Supply one unnamed argument to override the default: env <- env(base_env(), a = 1, b = "foo") identical(env_parent(env), base_env())
#> [1] TRUE
# child_env() lets you specify a parent: child <- child_env(env, c = "bar") identical(env_parent(child), env)
#> [1] TRUE
# This child environment owns `c` but inherits `a` and `b` from `env`: env_has(child, c("a", "b", "c", "d"))
#> a b c d #> FALSE FALSE TRUE FALSE
env_has(child, c("a", "b", "c", "d"), inherit = TRUE)
#> a b c d #> TRUE TRUE TRUE FALSE
# `parent` is passed to as_environment() to provide handy # shortcuts. Pass a string to create a child of a package # environment: child_env("rlang")
#> <environment: 0x5ca3928>
env_parent(child_env("rlang"))
#> <environment: package:rlang> #> attr(,"name") #> [1] "package:rlang" #> attr(,"path") #> [1] "/home/travis/build/r-lib/rlang"
# Or `NULL` to create a child of the empty environment: child_env(NULL)
#> <environment: 0x5be11f0>
env_parent(child_env(NULL))
#> <environment: R_EmptyEnv>
# The base package environment is often a good default choice for a # parent environment because it contains all standard base # functions. Also note that it will never inherit from other loaded # package environments since R keeps the base package at the tail # of the search path: base_child <- child_env("base") env_has(base_child, c("lapply", "("), inherit = TRUE)
#> lapply ( #> TRUE TRUE
# On the other hand, a child of the empty environment doesn't even # see a definition for `(` empty_child <- child_env(NULL) env_has(empty_child, c("lapply", "("), inherit = TRUE)
#> lapply ( #> FALSE FALSE
# Note that all other package environments inherit from base_env() # as well: rlang_child <- child_env("rlang") env_has(rlang_child, "env", inherit = TRUE) # rlang function
#> env #> TRUE
env_has(rlang_child, "lapply", inherit = TRUE) # base function
#> lapply #> TRUE
# Both env() and child_env() support tidy dots features: objs <- list(b = "foo", c = "bar") env <- env(a = 1, !!! objs) env$c
#> [1] "bar"
# You can also unquote names with the definition operator `:=` var <- "a" env <- env(!!var := "A") env$a
#> [1] "A"
# Use new_environment() to create containers with the empty # environment as parent: env <- new_environment() env_parent(env)
#> <environment: R_EmptyEnv>
# Like other new_ constructors, it takes an object rather than dots: new_environment(list(a = "foo", b = "bar"))
#> <environment: 0x7191160>