In one of my packages I use the .onAttach
hook to run some R code and then use assign
to make the value available as one of the package variables. I do it because variable
depends on the content of some file, which can change between one session and the other. The code I use is like:
.onAttach <- function(libname, pkgname) {
variable <- some_function()
assign("variable", variable, envir = as.environment("package:MyRPackage"))
}
When I attach the package with library(MyRpackage)
I can use variable
.
However it is not possible to do something like MyRPackage::variable
(unless I have already attached the package with library(MyRpackage)
.
I know this is because I should put that code in the .onLoad
hook, however I can't make the assignment so that it works.
I have tried
.onLoad <- function(libname, pkgname) {
variable <- some_function()
assign("variable", variable, envir = as.environment("namesoace:MyRPackage"))
}
and
.onLoad <- function(libname, pkgname) {
variable <- some_function()
assign("variable", variable, envir = asNamespace("MyRPackage"))
}
but both of them fail with some error when I run MyRPackage:::variable
without using library
to attach the package.
What is the correct to do the assignment in the .onLoad hook?
There are essentially three ways:
assignInMyNamespace(…)
assign(…, envir = topenv())
ns$name = value
Although option 1 seems to be quite widespread, it actually requires more code, because you’ll first need to create a variable before you can overwrite it via assignInMyNamespace
:
myvar = NULL
.onLoad = function (libname, pkgname) {
assignInMyNamespace('myvar', value)
}
Failure to pre-declare the variable will lead to an error.
By contrast, assign
is perfectly capable of creating a new variable which hasn’t been declared before. We just have to tell R into which environment to assign the variable, and the function topenv()
provides this.
.onLoad = function (libname, pkgname) {
assign('myvar', value, envir = topenv())
}
And of course we don’t need assign()
(or assignInMyNamespace()
) if we define a namespace object and subset-assign into it:
.onLoad = function (libname, pkgname) {
ns = topenv()
ns$myvar = value
}
For my own code I am gravitating towards the last option.
Following the approach in this answer to a related question, you can change your .onLoad()
function like so:
.onLoad <- function(libname, pkgname) {
variable <- some_function()
assign("variable", variable, envir = parent.env(environment()))
}
Then you can access variable
without attaching the package using MyRPackage:::variable
. I don't know what you do with some_function()
, so I tried the following with a dummy package:
.onLoad <- function(libname, pkgname) {
variable <- 42
assign("variable", variable, envir = parent.env(environment()))
}
And in a fresh R session the result was
> MyRPackage:::variable
[1] 42
From Hadley Wickham's Advanced R:
There are four special environments:
...
- The environment() is the current environment.
...
You can list the bindings in the environment’s frame with ls() and see its parent with parent.env().
So, if we modify the .onLoad()
function further, we can see this in action:
.onLoad <- function(libname, pkgname) {
print(environment()) # For demonstration purposes only;
print(parent.env(environment())) # Don't really do this.
variable <- 42
assign("variable", variable, envir = parent.env(environment()))
}
Then starting an R session results in
<environment: 0x483da88>
<environment: namespace:MyRPackage>
being printed to the console at the start of the session. This allows you to assign variable
in the environment namespace:MyRPackage
even though trying assign("variable", variable, envir = namespace:MyRPackage)
would result in the error
Error: package or namespace load failed for ‘MyRPackage’:
.onLoad failed in loadNamespace() for 'MyRPackage', details:
call: get(name, envir = ns, inherits = FALSE)
error: object 'namespace' not found
when installing the package.
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