[R-pkg-devel] Is there a better way ...?
On Thu, Oct 21, 2021 at 12:15 PM Rolf Turner <r.turner at auckland.ac.nz> wrote:
On Thu, 21 Oct 2021 02:03:41 -0400 Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
On 21/10/2021 12:40 a.m., Andrew Simmons wrote:
I think the simplest answer is to store the variable in the
functions frame. I'm assuming here that the only plot.foo needs
access to .fooInfo, if not this can be changed.
plot.foo <- function (...)
{
.fooInfo
}
environment(plot.foo) <- new.env()
evalq({
.fooInfo <- NULL
}, environment(plot.foo))
Make your function, and do whatever you need with .fooInfo within
said function. Whenever you previously updated .fooInfo in the
global environment, update .fooInfo in plot.foo environment instead.
Also, because .fooInfo is not stored in the package's frame, it
won't be locked when the namespace is sealed. If you created it at
the toplevel, that would create some issues. But this works fine.
I agree with the final result, but I'd write the code differently:
plot.foo <- local({
.fooInfo <- NULL
function (...) { ... }
})
creates an environment, puts .fooInfo into it with value NULL, then
creates a function with that environment attached and returns it.
I think Andrew's approach will work, but changing a function's
environment always worries me. Using local(), the function assigned
to plot.foo never has a different environment than the one it ends up
with (and I don't need to remember how evalq() works).
Thanks everyone for these suggestions. They seem a great deal less shaganappi/kludgy than my previous approaches. I've never really felt totally comfortable with the environment concept, despite have used it quite a bit (basically in a hammer-and-hope style.) Can anyone comment on the difference between Deepayan's suggestion (create a new environment in the package) and Duncan's suggestion (create an environment that is local to plot.foo())? Are there pros and cons between the two?
My suggestion is having a package-specific environment, and Duncan's is to have a function-specific environment. If you only need this for this one function, then that should be good enough. If you eventually want to access the persistent information from multiple functions, having a package-specific environment would be more useful. I'm not sure what you are trying to do, but I can't see how you can do something sensible with a function-specific environment if someone does plot.foo(something) plot.default(1:10) plot.foo(something else, add = TRUE) So maybe you would eventually want to set a hook (?setHook) for plot.new to ensure that no other plot has been created in between, which could write into this package-specific environment.
And Deepayan: what is the rationale for not exporting the new environment that you suggest creating? Presumably this guards against something. What? I'd just like to extend my (currently minimal) comprehension of the issues.
Nothing other than the usual reason for not exporting things unnecessarily, which is to not pollute the user workspace.
I must admit that Andrew's suggestion kind of overwhelms and bewilders me. I really have no idea what evalq() does. I guess I could RTFM, but the thought of doing that scares me! :-)
Andrew's suggestion looks more complicated than it is. Think of
.fooInfo as a "global" variable, just in your package namespace rather
than .GlobalEnv, so you could do (in your package code)
.fooInfo <- NULL
plot.foo <- function(...)
{
if (is.null(.fooInfo)) ... # use .fooInfo
.fooInfo <<- something # set .fooInfo
}
Andrew suggested a separate (and unnamed) environment to store both
.fooInfo and plot.foo, so the setting part becomes a bit more
complicated (but accessing becomes safer in the sense that no other
function can access .fooInfo).
My suggestion is essentially similar, except that you can use <-
instead of <<- because it's an environment.
.fooEnv <- new.env()
plot.foo <- function(...)
{
if (is.null(.fooEnv$info)) ... # use .fooEnv$info
.fooEnv$info <- something # set .fooEnv$info
}
Best,
-Deepayan
Thanks again everybody. cheers, Rolf -- Honorary Research Fellow Department of Statistics University of Auckland Phone: +64-9-373-7599 ext. 88276