Skip to content

Instantly share code, notes, and snippets.

@DarwinAwardWinner
Last active December 27, 2015 08:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DarwinAwardWinner/7298557 to your computer and use it in GitHub Desktop.
Save DarwinAwardWinner/7298557 to your computer and use it in GitHub Desktop.
Proof of concept protection against free variables. The purpose is to avoid passing a function to a subprocess for parallel evaluation when that function depends on variables that are only available in the parent process.
library(codetools)
getNonPackageVars <- function (pos=-1L, envir=as.environment(pos)) {
npvarnames <- c()
while (TRUE) {
if (identical(envir, emptyenv()) ||
identical(envir, .BaseNamespaceEnv)) {
## If we hit the empty env, then we started in a package
## namespace, so there are no non-package vars.
return(character(0))
}
if (identical(envir, baseenv()))
message("Looking in env: ", capture.output(print(envir)))
npvarnames <- c(npvarnames, ls(envir=envir))
if (identical(envir, globalenv())) {
## After we process the global env, we're done
break()
}
envir <- parent.env(envir)
}
unique(npvarnames)
}
getNonPackageFreeVars <- function (fun) {
npvars <- getNonPackageVars(environment(fun))
fun.freevars <- findGlobals(fun)
intersect(fun.freevars, npvars)
}
do.call.if.ok <- function(what, ...) {
what <- match.fun(what)
badvars <- getNonPackageFreeVars(what)
if (length(badvars) > 0) {
stop("Function contains free variables: ", deparse(badvars))
}
do.call(what=what, ...)
}
x <- 5
okfunc <- function (a, b) a + b
freevarfunc <- function (a) a + x + y
getNonPackageFreeVars(okfunc)
getNonPackageFreeVars(freevarfunc)
getNonPackageFreeVars(rnorm)
do.call.if.ok(okfunc, list(a=1, b=2))
do.call.if.ok(freevarfunc, list(a=1))
do.call.if.ok(rnorm, list(10))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment