I'd like to create a function prevent_side_effects(expr, envir)
that executes expr
in environment envir
but has read-only access to the variables and functions in envir
and all parent environments.
Is locking envir
and locking all the symbols therein the only way to do this, or is there a better way? If I go the locking route is it necessary to walk up the graph of parent environments and lock those as well?
Here is a reproducible example that demonstrates how this function would behave:
grandparent.env <- environment()
parent.env <- new.env(parent=grandparent.env)
env <- new.env(parent=parent.env)
env$x <- 1
parent.env$y <- 2
grandparent.env$z <- 3
grandparent.env$f <- function() cat('function defined in grandparent env\n')
out <- prevent_side_effects(envir=env, expr={
cat(sprintf('%i %i %i\n', x, y, z))
#> 1 2 3
f()
#> function defined in grandparent env
# The following all throw errors or just define new local variables such
# that variables in env, parent.env, and grandparent.env are masked but
# unchanged.
x <<- 1000
y <<- 1000
z <<- 1000
x <- 4
y <- 5
z <- 6
cat(sprintf('%i %i %i\n', x, y, z))
#> 4 5 6
})
cat(sprintf('%i %i %i\n', x, y, z))
#> 1 2 3