1

My understanding of callr::r is that the function I am providing is evaluated in a new session of R. If (for whatever reason) I want to keep the .GlobalEnv of this session, I thought I could do it like this:

i_am_defined_on_global_level <- "here"
res <- callr::r(function() .GlobalEnv)
names(res)
# [1] "res"                          ".Random.seed"                
# [3] "i_am_defined_on_global_level"

But apparently .GlobalEnv within the anonymous function refers to the global environment of the calling environment (otherwise I would not see i_am_defined_on_global_level).

So how would I return the .GlobalEnv of the session in which the function is called?

Background

I have a large Rmarkdown document and because of current bugs in Rstudio I cannot run run all chunks as I have non R chunks in my document. Thus, I have to run each chunk "by hand" which is rather cumbersome.

Thus, I wanted to call render not via the knit button, but from the command line, where I have control over the environment in which the document is rendered and thus could keep all intermediate results. I thought it would be a good idea to do so in a new session to avoid name conflicts, thus I wanted to rely on callr::r:

render_report <- function(report = "myreport.Rmd",
                          report_dir = here::here("report")) {
   report_env <- callr::r(function(report, report_dir) {
      rmarkdown::render(file.path(report_dir, report), 
                        output_dir = report_dir,
                        envir = globalenv())
      globalenv()
   }, list(report = report, 
           report_dir = report_dir),
   show = TRUE,
   spinner = FALSE)
   report_env
}

results <- render_report()

But results refers then only to the original GlobalEnv.

thothal
  • 16,690
  • 3
  • 36
  • 71

1 Answers1

3

[Edited to correct the first sentence.] The problem is that .GlobalEnv is saved in a weird way. It just refers to the current global environment, whatever that is. So anything you create in your function will disappear, and res will point to your current global environment.

To see the globals in the callr::r environment, I think you'll have to copy them to a new environment and return that. E.g.

i_am_defined_on_global_level <- "here"
res <- callr::r(function() {
  i_am_in_the_callr_global_env <<- "there"
  returnenv <- as.list(globalenv())
  list2env(returnenv)
  })
names(res)
#> [1] "i_am_in_the_callr_global_env"

Created on 2023-01-12 with reprex v2.0.2

user2554330
  • 37,248
  • 4
  • 43
  • 90
  • Beautiful, works like a charm. DO you have by any chance any reference docs where this rather weired behaviour is explained? I thought because of lazy evaluation `globalenv` is not evaluated but before it is called - in this moment it should refer to the global env of `callr`. So for some very strange reason, it seems to be evaluated before which is very counterintuitive. So any docs with this respect would be helpful. How did you find out? – thothal Jan 13 '23 at 08:00
  • 1
    I think the weirdness is mainly to do with serialization. The R Internals manual lists objects that are special this way: "Some objects are written as if they were SEXPTYPEs: such pseudo-SEXPTYPEs cover R_NilValue, R_EmptyEnv, R_BaseEnv, R_GlobalEnv, R_UnboundValue, R_MissingArg and R_BaseNamespace." (The "R_" prefix refers to the C variable for the object.) – user2554330 Jan 13 '23 at 09:58