I am studying "environment" concept in R.
Now I know emptyenv()
is the parent of all environments and it has no parent, but is there a way to list all environments in current R session or say children of emptyenv()
?
My solution is looking for environments recursively. We could do it because of the fact that additional/new environments have to be create in a visible/known place. Still, there might be some lesser edge cases like environments inside functions or R6 classes:
fun <- function() {
ee <- new.env()
fun2 <- function() {
eee <- new.env()
}
return(1)
}
Another thing will be to grab e.g. environment of the function body, inside {}. It will be created during function evaluation not creation. This might be almost impossible.
I am demanding that the object recognized as an environment - is.environment
and inherits(e, "environment")
. The latter condition protecting us against objects like ggproto
loaded with ggplot2
.
set.seed(1234)
# New environments - x7
#######################
eval(quote(ee <- new.env(parent = baseenv())))
eval(quote(ee1 <- new.env(parent = baseenv())), envir = ee)
ee2 <- new.env()
ee3 <- new.env(parent = ee2)
eval(quote(ee4 <- new.env(parent = baseenv())), envir = ee3)
eval(quote(ee5 <- new.env()), envir = baseenv())
eval(quote(ee6 <- new.env(parent = .GlobalEnv)), envir = ee3)
#######################
subenv <- function(env) {
envs <- unique(Filter(function(e) is.environment(e) && inherits(e, "environment"), lapply(ls(env), function(x) get(x, env))))
unlist(append(envs, lapply(envs, subenv)))
}
search_all = function() {
ees <- unlist(append(.GlobalEnv, rlang::env_parents(.GlobalEnv)))
unname(unlist(lapply(ees, subenv)))
}
library(ggplot2)
search_all()
results:
> search_all()
[[1]]
<environment: 0x7f9c75e66e10>
[[2]]
<environment: 0x7f9c75e65600>
[[3]]
<environment: 0x7f9c75e68e80>
[[4]]
<environment: 0x7f9c75e65e88>
[[5]]
<environment: 0x7f9c75e67ec0>
[[6]]
<environment: 0x7f9c75e6df38>
[[7]]
<environment: 0x7f9c75e6ef30>
EDIT:
This function might be used to maximize environments visibility.
new.env <- function(...) {
ee <- base::new.env(...)
if(!identical(parent.frame(), .GlobalEnv)) {
assign(paste0("env_", data.table::address(ee)), ee, envir = .GlobalEnv)
}
ee
}
Unfortunately when some package is built it will be using base::new.env by default. Even assignInNamespace
might not be satisfactory here.
Rather than look at all of the children of the empty environment, we can look at the parents of the global environment. This is an imperfect solution because some environments can exist is ways that are not parents of the global environment, but it's at least a partial solution.
The following recursive function will return a list of all environments exist as parents (grandparents, etc.) of the env
argument. If you don't specify an environment, the global environment is used.
allParents = function(env = globalenv(), result = list()) {
result = c(list(parent.env(env)), result)
if(!identical(result[[1]], emptyenv())) {
result <- allParents(result[[1]], result)
}
return(result)
}
allParents()
yields, for instance:
[[1]]
<environment: R_EmptyEnv>
[[2]]
<environment: base>
[[3]]
<environment: 0x55b78fe34790>
attr(,"name")
[1] "org:r-lib"
[[4]]
<environment: 0x55b78bc4dfe8>
attr(,"name")
[1] "Autoloads"
[[5]]
<environment: package:methods>
attr(,"name")
[1] "package:methods"
attr(,"path")
[1] "/usr/lib/R/library/methods"
[[6]]
<environment: package:datasets>
attr(,"name")
[1] "package:datasets"
attr(,"path")
[1] "/usr/lib/R/library/datasets"
[[7]]
<environment: package:utils>
attr(,"name")
[1] "package:utils"
attr(,"path")
[1] "/usr/lib/R/library/utils"
[[8]]
<environment: package:grDevices>
attr(,"name")
[1] "package:grDevices"
attr(,"path")
[1] "/usr/lib/R/library/grDevices"
[[9]]
<environment: package:graphics>
attr(,"name")
[1] "package:graphics"
attr(,"path")
[1] "/usr/lib/R/library/graphics"
[[10]]
<environment: package:stats>
attr(,"name")
[1] "package:stats"
attr(,"path")
[1] "/usr/lib/R/library/stats"
[[11]]
<environment: 0x55b78d81bd78>
attr(,"name")
[1] "tools:rstudio"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With