Learn R Programming

rlang (version 0.1)

env_bind: Bind symbols to objects in an environment

Description

These functions create bindings in an environment. The bindings are supplied through ... as pairs of names and values or expressions. env_bind() is equivalent to evaluating a <- expression within the given environment. This function should take care of the majority of use cases but the other variants can be useful for specific problems.

  • env_bind() takes named values. The arguments are evaluated once (with explicit splicing) and bound in .env. env_bind() is equivalent to base::assign().

  • env_bind_fns() takes named functions and creates active bindings in .env. This is equivalent to base::makeActiveBinding(). An active binding executes a function each time it is evaluated. env_bind_fns() takes dots with implicit splicing, so that you can supply both named functions and named lists of functions.

    If these functions are closures they are lexically scoped in the environment that they bundle. These functions can thus refer to symbols from this enclosure that are not actually in scope in the dynamic environment where the active bindings are invoked. This allows creative solutions to difficult problems (see the implementations of dplyr::do() methods for an example).

  • env_bind_exprs() takes named expressions. This is equivalent to base::delayedAssign(). The arguments are captured with exprs() (and thus support call-splicing and unquoting) and assigned to symbols in .env. These expressions are not evaluated immediately but lazily. Once a symbol is evaluated, the corresponding expression is evaluated in turn and its value is bound to the symbol (the expressions are thus evaluated only once, if at all).

Usage

env_bind(.env, ...)

env_bind_exprs(.env, ..., .eval_env = caller_env())

env_bind_fns(.env, ...)

Arguments

.env

An environment or an object bundling an environment, e.g. a formula, quosure or closure. This argument is passed to get_env().

...

Pairs of names and expressions, values or functions. These dots support splicing (with varying semantics, see above) and name unquoting.

.eval_env

The environment where the expressions will be evaluated when the symbols are forced.

Value

The input object .env, with its associated environment modified in place, invisibly.

Side effects

Since environments have reference semantics (see relevant section in env() documentation), modifying the bindings of an environment produces effects in all other references to that environment. In other words, env_bind() and its variants have side effects.

As they are called primarily for their side effects, these functions follow the convention of returning their input invisibly.

Examples

Run this code
# NOT RUN {
# env_bind() is a programmatic way of assigning values to symbols
# with `<-`. We can add bindings in the current environment:
env_bind(get_env(), foo = "bar")
foo

# Or modify those bindings:
bar <- "bar"
env_bind(get_env(), bar = "BAR")
bar

# It is most useful to change other environments:
my_env <- env()
env_bind(my_env, foo = "foo")
my_env$foo

# A useful feature is to splice lists of named values:
vals <- list(a = 10, b = 20)
env_bind(my_env, !!! vals, c = 30)
my_env$b
my_env$c

# You can also unquote a variable referring to a symbol or a string
# as binding name:
var <- "baz"
env_bind(my_env, !!var := "BAZ")
my_env$baz


# env_bind() and its variants are generic over formulas, quosures
# and closures. To illustrate this, let's create a closure function
# referring to undefined bindings:
fn <- function() list(a, b)
fn <- set_env(fn, child_env("base"))

# This would fail if run since `a` etc are not defined in the
# enclosure of fn() (a child of the base environment):
# fn()

# Let's define those symbols:
env_bind(fn, a = "a", b = "b")

# fn() now sees the objects:
fn()

# env_bind_exprs() assigns expressions lazily:
env <- env()
env_bind_exprs(env, name = cat("forced!\n"))
env$name
env$name

# You can unquote expressions. Note that quosures are not
# supported, only raw expressions:
expr <- quote(message("forced!"))
env_bind_exprs(env, name = !! expr)
env$name

# You can create active bindings with env_bind_fns()
# Let's create some bindings in the lexical enclosure of `fn`:
counter <- 0

# And now a function that increments the counter and returns a
# string with the count:
fn <- function() {
  counter <<- counter + 1
  paste("my counter:", counter)
}

# Now we create an active binding in a child of the current
# environment:
env <- env()
env_bind_fns(env, symbol = fn)

# `fn` is executed each time `symbol` is evaluated or retrieved:
env$symbol
env$symbol
eval_bare(quote(symbol), env)
eval_bare(quote(symbol), env)
# }

Run the code above in your browser using DataLab