Henrik Bengtsson
2011-Nov-24 02:36 UTC
[Rd] capture.output(eval(..., envir)) not evaluate in the expected(?) environment
I've noticed the following oddity where capture.output() prevents eval() from evaluating an expression in the specified environment. I'm not sure if it is an undocumented feature or a bug. It caused me many hours of troubleshooting. By posting it here, it might save someone else from doing the same exercise. Start by defining foo() which evaluates an expression locally in a given environment and catches the output via capture.output(): foo <- function(..., envir=parent.frame()) { capture.output({ eval(substitute({x <- 1}), envir=envir) }) } # foo() Then call:> suppressWarnings(rm(x)); foo(envir=globalenv()); print(x);character(0) [1] 1 This works as expected. However, if argument 'envir' is not specified explicitly, you get:> suppressWarnings(rm(x)); foo(); str(x);character(0) Error in str(x) : object 'x' not found which shows that the internal expression of foo() is *not* evaluated in the parent.frame(), i.e. the caller of foo(), which here should be globalenv(). It appears that capture.output() prevents this, because by dropping the latter: foo <- function(..., envir=parent.frame()) { eval(substitute({x <- 1}), envir=envir) } # foo() it works:> suppressWarnings(rm(x)); foo(); str(x);[1] 1 The workaround when still using capture.output() is to force an explicit evaluation of argument 'envir' inside of foo() before: foo <- function(..., envir=parent.frame()) { stopifnot(is.environment(envir)) # Workaround capture.output({ eval(substitute({x <- 1}), envir=envir) }) } # foo() which gives:> suppressWarnings(rm(x)); foo(); str(x);character(0) num 1 This occurs with R v2.14.0 patched and R devel:> sessionInfo()R version 2.14.0 Patched (2011-11-20 r57720) Platform: x86_64-pc-mingw32/x64 (64-bit) locale: [1] LC_COLLATE=English_United States.1252 [2] LC_CTYPE=English_United States.1252 [3] LC_MONETARY=English_United States.1252 [4] LC_NUMERIC=C [5] LC_TIME=English_United States.1252 attached base packages: [1] stats graphics grDevices utils datasets methods base> sessionInfo()R Under development (unstable) (2011-11-20 r57720) Platform: x86_64-pc-mingw32/x64 (64-bit) locale: [1] LC_COLLATE=English_United States.1252 [2] LC_CTYPE=English_United States.1252 [3] LC_MONETARY=English_United States.1252 [4] LC_NUMERIC=C [5] LC_TIME=English_United States.1252 attached base packages: [1] stats graphics grDevices utils datasets methods base /Henrik
Simon Urbanek
2011-Nov-24 02:56 UTC
[Rd] capture.output(eval(..., envir)) not evaluate in the expected(?) environment
IMHO this has nothing to do with capture.output() per se - it's simply lazy evaluation that gets you. Add force(envir) before capture.output and it works as you expected - the parent.frame() will be different inside capture.output than outside. Cheers, Simon On Nov 23, 2011, at 9:36 PM, Henrik Bengtsson wrote:> I've noticed the following oddity where capture.output() prevents > eval() from evaluating an expression in the specified environment. > I'm not sure if it is an undocumented feature or a bug. It caused me > many hours of troubleshooting. By posting it here, it might save > someone else from doing the same exercise. > > Start by defining foo() which evaluates an expression locally in a > given environment and catches the output via capture.output(): > > foo <- function(..., envir=parent.frame()) { > capture.output({ > eval(substitute({x <- 1}), envir=envir) > }) > } # foo() > > Then call: > >> suppressWarnings(rm(x)); foo(envir=globalenv()); print(x); > character(0) > [1] 1 > > This works as expected. However, if argument 'envir' is not specified > explicitly, you get: > >> suppressWarnings(rm(x)); foo(); str(x); > character(0) > Error in str(x) : object 'x' not found > > which shows that the internal expression of foo() is *not* evaluated > in the parent.frame(), i.e. the caller of foo(), which here should be > globalenv(). It appears that capture.output() prevents this, because > by dropping the latter: > > foo <- function(..., envir=parent.frame()) { > eval(substitute({x <- 1}), envir=envir) > } # foo() > > it works: > >> suppressWarnings(rm(x)); foo(); str(x); > [1] 1 > > The workaround when still using capture.output() is to force an > explicit evaluation of argument 'envir' inside of foo() before: > > foo <- function(..., envir=parent.frame()) { > stopifnot(is.environment(envir)) # Workaround > capture.output({ > eval(substitute({x <- 1}), envir=envir) > }) > } # foo() > > which gives: >> suppressWarnings(rm(x)); foo(); str(x); > character(0) > num 1 > > This occurs with R v2.14.0 patched and R devel: > >> sessionInfo() > R version 2.14.0 Patched (2011-11-20 r57720) > Platform: x86_64-pc-mingw32/x64 (64-bit) > > locale: > [1] LC_COLLATE=English_United States.1252 > [2] LC_CTYPE=English_United States.1252 > [3] LC_MONETARY=English_United States.1252 > [4] LC_NUMERIC=C > [5] LC_TIME=English_United States.1252 > > attached base packages: > [1] stats graphics grDevices utils datasets methods base > >> sessionInfo() > R Under development (unstable) (2011-11-20 r57720) > Platform: x86_64-pc-mingw32/x64 (64-bit) > > locale: > [1] LC_COLLATE=English_United States.1252 > [2] LC_CTYPE=English_United States.1252 > [3] LC_MONETARY=English_United States.1252 > [4] LC_NUMERIC=C > [5] LC_TIME=English_United States.1252 > > attached base packages: > [1] stats graphics grDevices utils datasets methods base > > /Henrik > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > >
Possibly Parallel Threads
- MITOOLS: Error in eval(expr, envir, enclos) : invalid 'envir' argument
- Finding the first value without warning in a loop
- Error in eval(expr, envir, enclos) : object 'Rayos' not found???
- Error in eval(expr, envir, enclos) : numeric envir arg not of length one
- bug: sticky symbol refs? (PR#9555)