Duncan Murdoch
2021-Dec-27 13:25 UTC
[R] How to modify object's code living in some environment?
On 27/12/2021 8:06 a.m., Grzegorz Smoli?ski wrote:> Hi, > > I know it is possible to find the environment in which some object > lives using the 'environment()' function and the name of this object, > but how to modify code of this object after this? Below is MRE:You are misunderstanding the relation between environments and functions. However, your understanding is also being messed up by a bug in R, so it's not entirely your fault. More details below:> > test <- function() 1 > > test() # 1 > > environment(test)$test <- eval(parse(text = "function() 2"))First: while it's usually true that function f will be found in environment(f), these are really separate concepts. The environment of a function is where it will start looking for non-local variables. It is initially the environment in which the function definition is evaluated. The environment holding a function can be completely different. This most commonly shows up when you have functions that create other functions. For example, factory <- function(x) { force(x) function() print(x) } f <- factory(3) f() which will print 3. Here environment(f) is the evaluation frame of the call to factory(3), while f is not stored there, it is stored in the global environment. (If you run ls(environment(f)) you won't see "f" listed, only "x".) In your first line "test <- function() 1" you create a function named test in the global environment whose environment is also the global environment. The third line should do what you want, i.e. put the new definition into the environment of the test function, using the name test, but it doesn't: I think that's a bug in R. It should be equivalent to .GlobalEnv$test <- eval(parse(text = "function() 2")) or test <- eval(parse(text = "function() 2")) but as you saw, it's not. They do what you were expecting your third line to do.> > test() # still 1 > > .GlobalEnv$test <- eval(parse(text = "function() 3")) > > test() # 3 > > The context is I have shiny app which code I would like to modify (add > something) and the only way to refer to this environment I know is to > use 'environment()' (as I see, those functions do not live in > .GlobalEnv), but as you can see above, I can't use it to modify the > code.You can, as long as you work around the bug in R. Just change that third line into two statements: e <- environment(test) e$test <- eval(parse(text = "function() 2")) Duncan Murdoch
Duncan Murdoch
2021-Dec-27 13:27 UTC
[R] How to modify object's code living in some environment?
On 27/12/2021 8:25 a.m., Duncan Murdoch wrote:> On 27/12/2021 8:06 a.m., Grzegorz Smoli?ski wrote: >> Hi, >> >> I know it is possible to find the environment in which some object >> lives using the 'environment()' function and the name of this object, >> but how to modify code of this object after this? Below is MRE: > > You are misunderstanding the relation between environments and > functions. However, your understanding is also being messed up by a bug > in R, so it's not entirely your fault. > > More details below: >> >> test <- function() 1 >> >> test() # 1 >> >> environment(test)$test <- eval(parse(text = "function() 2")) > > First: while it's usually true that function f will be found in > environment(f), these are really separate concepts. > > The environment of a function is where it will start looking for > non-local variables. It is initially the environment in which the > function definition is evaluated. > > The environment holding a function can be completely different. This > most commonly shows up when you have functions that create other > functions. For example, > > factory <- function(x) { > force(x) > function() print(x) > } > > f <- factory(3) > f() > > which will print 3. Here environment(f) is the evaluation frame of the > call to factory(3), while f is not stored there, it is stored in the > global environment. (If you run ls(environment(f)) you won't see "f" > listed, only "x".) > > In your first line "test <- function() 1" you create a function named > test in the global environment whose environment is also the global > environment. > > The third line should do what you want, i.e. put the new definition into > the environment of the test function, using the name test, but it > doesn't: I think that's a bug in R. It should be equivalent to > > .GlobalEnv$test <- eval(parse(text = "function() 2")) > > or > > test <- eval(parse(text = "function() 2")) > > but as you saw, it's not. They do what you were expecting your third > line to do. > >> >> test() # still 1 >> >> .GlobalEnv$test <- eval(parse(text = "function() 3")) >> >> test() # 3 >> >> The context is I have shiny app which code I would like to modify (add >> something) and the only way to refer to this environment I know is to >> use 'environment()' (as I see, those functions do not live in >> .GlobalEnv), but as you can see above, I can't use it to modify the >> code. > > You can, as long as you work around the bug in R. Just change that > third line into two statements: > > e <- environment(test) > e$test <- eval(parse(text = "function() 2")) >And I forgot to mention, as Ivan did, that this might not do what you want, because of the difference in the concepts of "environment(f)" and "environment where f is found". Duncan Murdoch
Duncan Murdoch
2021-Dec-27 17:28 UTC
[R] How to modify object's code living in some environment?
On 27/12/2021 8:25 a.m., Duncan Murdoch wrote:> On 27/12/2021 8:06 a.m., Grzegorz Smoli?ski wrote: >> Hi, >> >> I know it is possible to find the environment in which some object >> lives using the 'environment()' function and the name of this object, >> but how to modify code of this object after this? Below is MRE: > > You are misunderstanding the relation between environments and > functions. However, your understanding is also being messed up by a bug > in R, so it's not entirely your fault.Actually this isn't a bug in R, it is working as documented. For a detailed explanation, see the response to my bug report here: https://bugs.r-project.org/show_bug.cgi?id=18269 . For a quick idea: "complex assignments" are assignments where there is a complex expression on the left hand side, e.g. environment(test)$test <- ... The way these are documented to work (in the R Language Definition manual) makes intuitive sense when you are working with regular R objects, but environments are "mutable" objects: assigning them to a new name doesn't make a new copy, just a new reference. That causes the definition of the complex assignment above to work in an unintuitive way. Conclusion: you should avoid using calls like environment(f) on the left hand side of assignments, especially as part of a larger expression. Break up the statement into steps like I did below:> e <- environment(test) > e$test <- eval(parse(text = "function() 2"))The same advice would apply to a function that returned an R6 object or a mutable object from the methods package (which are really environments in disguise), as well as some other exotic objects. Duncan Murdoch