Skip to content

Instantly share code, notes, and snippets.

@lionel-
Last active November 19, 2019 09:55
Show Gist options
  • Save lionel-/2ae557878c89737c58b2051656d6952d to your computer and use it in GitHub Desktop.
Save lionel-/2ae557878c89737c58b2051656d6952d to your computer and use it in GitHub Desktop.
makeDelayedBinding <- function(sym,
expr,
eval.env = parent.frame(1),
assign.env = parent.frame(1)) {
expr <- substitute(expr)
value <- NULL
forced <- FALSE
forceDelayed <- function() {
if (!forced) {
value <- eval(expr, eval.env)
eval.env <<- NULL # Release env for gc
forced <<- TRUE
}
value
}
class(forceDelayed) <- c("forceDelayed", "function")
makeActiveBinding(sym, forceDelayed, assign.env)
}
# By default, returns `FALSE` if the delayed binding has been forced.
# Pass `forced = NULL` if state doesn't matter, or `forced = TRUE`
# to return `TRUE` if the delayed binding has been forced.
bindingIsDelayed <- function(sym, env, forced = FALSE) {
if (!bindingIsActive(sym, env)) {
return(FALSE)
}
fn <- activeBindingFunction(sym, env)
if (!inherits(fn, "forceDelayed"))) {
return(FALSE)
}
is.null(forced) || identical(get("forced", envir = environment(fn)), forced)
}
# Can use the accessors on any delayed binding, forced or not.
# If delayed binding is forced, the environment is NULL.
delayedBindingExpression <- function(sym, env) {
stopifnot(bindingIsDelayed(sym, env, forced = NULL))
fn <- activeBindingFunction(sym, env)
get("expr", envir = environment(fn))
}
delayedBindingEnvironment <- function(sym, env) {
stopifnot(bindingIsDelayed(sym, env, forced = NULL))
fn <- activeBindingFunction(sym, env)
get("eval.env", envir = environment(fn))
}
@lionel-
Copy link
Author

lionel- commented Nov 18, 2019

activeBindingFunction() would throw if not applied of an active binding. Safe usage would be:

if (bindingIsActive(sym, env) {
  activeBindingFunction(sym, env)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment