0

According to this post, environment() function is the function to call a current environment.

However, I found that at least that is not the case in eval function, with following examples.

.env <- new.env()
.env$info$progress <- 3
.expr <- "environment()$info$progress <- 5"
eval(parse(text = .expr), envir = .env, enclos = .env)

> invalid (NULL) left side of assignment

I also tried assign function, but it does not work either

.env <- new.env()
.env$info$progress <- 3
.expr <- "assign(info$progress, 11, envir = environment())"
eval(parse(text = .expr), envir = .env, enclos = .env)

> Error in assign(info$progress, 11, envir = environment()) :
> invalid first argument

So environment function failed to find current environment in eval.

I would appreciate if anyone lets me know how to access current environment in above examples or how to move-around this issue in eval.

Kim
  • 1,768
  • 2
  • 14
  • 24
  • You can't access a function's current environment by calling the function and passing `environment()` as an argument, as that will evaluate `environment()` as the environment where the function is called (e.g. `ff = function(env) c(env, environment()); ff(environment())`). Could you explain your ultimate goal? There, probably, exists a way to build calls and use environments with appropriate R objects rather than characters to parse. – alexis_laz Apr 22 '18 at 11:48

2 Answers2

1

environment() does what you think it does. The issue is with assigning directly to the result of a function call.

> new.env()$info$progress <- 3
Error in new.env()$info$progress <- 3 : 
  invalid (NULL) left side of assignment
> .env <- new.env()
> .env$info$progress <- 3
> evalq(identical(environment(), .env), envir = .env)
[1] TRUE
> evalq({ e <- environment(); e$info$progress <- 5 }, envir = .env)
> .env$info
$progress
[1] 5
gbrunick
  • 61
  • 2
0

The goal (which I thought was access to a defined environment) can be accomplished by considering the fact that no call to environment is needed. That function with a NULL argument doesn't retrieve anything useful. The .env object is an environment, so the assignment should just be into it:

.env <- new.env()

.env$info$progres <- 3
.expr <- ".env$info$progres <- 5"
eval(parse(text = .expr) )
#------------
> ls(envir=.env)
[1] "info"
> ?get
> get("info", envir=.env)
$progres
[1] 5

The environment assignment operation is supposed to put values into the environment of functions. I think it's probably undefined when you make an assignment into an unbound environment. I would not have thought that environment()$info$progres <- 5 would have succeeded in placing a value into .env since the target of environment(.)<- was NULL.

Responding to your comment: I'm not sure what was meant by "a current environment". There is "the current environment" and the .env-environment was not that environment (nor was it ever that environment, even for an instant). Creating an environment with new.env does not make it the current environment. It only creates an environment which allows you to store or retrieve objects in it by referencing its name.

 .env <- new.env()
 environment()
#<environment: R_GlobalEnv>

It isn't even on the search path. It's kind of "on the sidelines" waiting to be referenced.

> search()
 [1] ".GlobalEnv"         "package:acs"        "package:XML"        "package:acepack"    "package:abind"     
 [6] "package:downloader" "package:forcats"    "package:stringr"    "package:dplyr"      "package:purrr"     
[11] "package:readr"      "package:tidyr"      "package:tibble"     "package:tidyverse"  "tools:RGUI"        
[16] "package:grDevices"  "package:utils"      "package:datasets"   "package:graphics"   "package:rms"       
[21] "package:SparseM"    "package:Hmisc"      "package:ggplot2"    "package:Formula"    "package:stats"     
[26] "package:survival"   "package:sos"        "package:brew"       "package:lattice"    "package:methods"   
[31] "Autoloads"          "package:base"      
> ls(envir=.env)
[1] "info"

I find myself wondering if the goal was to use a more object-oriented style, and if so would recommend looking at the ?R6 help page and the section in the R Language Definition entitled: "5 Object-oriented programming".

After navigating through the help pages looking at the code for getAnywhere, ?find, ?ls, ?objects, I found a particular use of apropos that you might find interesting:

apropos("\\.", mode="environment")
[1] ".AutoloadEnv"  ".BaseNamespaceEnv" ".env" ".GenericArgsEnv" ".GlobalEnv" 
[6] ".userHooksEnv" 

If you use:

  apropos("." , mode="environment")`

..., constructed with the most generic pattern possible, you will also find the 100 or so ggproto-environments defined by ggplot2-functions, assuming you have that package loaded. I think Hadley's "Advanced Programming" may have more on this topic of interest because he defines a "environment list" class and functions to manipulate them.

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Thank you for the answer. However, that is not what it asked. In this answer, it uses a hard coded variable name ".env", and what I asked was about any function(s) to call a current environment the instead of a hard coded name. – Kim Apr 22 '18 at 07:53