DeanAttali
DeanAttali

Reputation: 26313

How to attach a function to my package's namespace after it's loaded?

This may seem like a weird question, but I do have a use case for it that I'm trying to figure out.

Suppose I'm writing a package and I have a function that I want to allow the user to alias to something else - the user provides the name of the function. I'm wondering what's the best way to achieve this?

#' @export
foo <- function() "Hello"
#' @export
addAlias <- function(x) assign(x, foo, envir = globalenv())

This is the behaviour I want to get - now the user can call addAlias("bar") and then if he calls bar() it'll be as if he called my function.

Obviously this is not a nice solution because it assigns to the global environment. Does anyone have feedback on what would be the best way to do this? A few methods I tried:

1. Assigning to globalenv

Just like I showed in the example. This seemed to work.

2. Assigning to the package's environment

addAlias <- function(x) assign(x, foo, as.environment("package:mypackage"))

This worked great for a while until I realized that it only works with devtools and not if the package is loaded properly because of locked environments

3. Attaching a new env to the searchpath

.onLoad <- function(libname, pkgname) {
  assign("aliases", new.env(), envir = parent.env(environment()))
  attach(aliases)
  invisible()
}

addAlias <- function(x) assign(x, foo, aliases)

This I don't like because of the use of attach. Is it warranted in this case? When would I detach?

4. Expose a separate named environment

#' @export
#' @keywords internal
aliases <- new.env()

addAlias <- function(x) assign(x, foo, aliases)

This works, but instead of being able to call bar(), the user needs to call alises$bar() or mypackage::aliases$bar(). I don't like that, but it was an interesting experiment. I also don't know if it's ok to export a variable like that?

Any help is appreciated

Upvotes: 1

Views: 142

Answers (1)

Randy Lai
Randy Lai

Reputation: 3174

I think a more appropriate way is to use closure.

#' @export
foo <- function() "Hello"
#' @export
getfoo <- function() {
    function(){
        # do anything, including running foo()
        foo()
    }
}

With this, you can do

> bar <- getfoo()
> bar()
[1] "Hello"

Upvotes: 1

Related Questions