der_grund
der_grund

Reputation: 1938

How to memoise a function at package startup in R

I work on an R package which wraps API calls. In order to reduce the number of actual calls and to speed things up, I memoise the function making the API call. To do so, I created the following function, which allows to set the cache directory:

memoise_fromJSON <- function(cache_dir = tempdir()) {
  memoise::memoise(jsonlite::fromJSON,
                   cache = memoise::cache_filesystem(cache_dir))
}

To create the memoised function I use

memoised_fromJSON <- memoise_fromJSON()

Now, since I need the memoised function many times within my package, I would like to memoise the function at package startup. I tried

.onLoad <- function(libname, pkgname) {
  memoised_fromJSON <- my_package:::memoise_fromJSON()
}

but I still need to run memoised_fromJSON <- memoise_fromJSON() to get it to work.

So my questions are:

  1. Is there a possibility to memoise a function at package startup?
  2. If so, how can I memoise the function in a way that it is not visible in the global environment?

I guess, the questions are somehow related. Is my understanding correct that my attempt with .onLoad() does not work because it creates the memoised function within the environment of .onLoad()?


PS: I am aware, that I cannot change the cache_dir at package loading, but I want to set a reasonable default which makes it possible to start without further ado. However, this keeps the possibility to change the cache directory if needed.

Upvotes: 5

Views: 536

Answers (2)

David Dorchies
David Dorchies

Reputation: 334

And why not directly declare the memoised function in your R sources ?

#' Memoised version of [jsonlite::fromJSON]
#' @inherit jsonlite::fromJSON
#' 
#' @export
memoised_fromJSON <- memoise::memoise(jsonlite::fromJSON,
                                      cache = memoise::cache_filesystem(tempdir()))

That should do the job without any notes or warnings in R CMD check.

Upvotes: 0

Konrad Rudolph
Konrad Rudolph

Reputation: 545618

You are performing a local assignment inside the onLoad function.

And you cannot simply perform a (package-) global assignment, since the package namespace is locked. What you can do is

  1. Create a new environment via new.env(parent = parent.env(environment()) (the parameter ensures that this environment finds objects defined inside your package namespace).
  2. Assign the memoised functions inside that environment.
  3. attach the environment. Now, this is generally frowned upon and will in fact earn you a red card from CRAN if you attempt to submit it. In fact, your .onLoad function mustn’t call attach since a user might want to use your package without attaching it. But I think it’s legitimate if you do this in .onAttach rather than .onLoad. The CRAN maintainers might not agree though, I’m afraid; then again, there’s precedence for CRAN packages that call attach under specific circumstances, e.g. {devtools}.

Upvotes: 3

Related Questions