Tal Galili
Tal Galili

Reputation: 25326

R Package development: overriding a function from one package with a function from another?

I am currently working on developing two packages, below is a simplified version of my problem:

In package A I have some functions (say "sum_twice"), and I it calls to another function inside the package (say "slow_sum"). However, in package B, I wrote another function (say "fast_sum"), with which I wish to replace the slow function in package A.

Now, how do I manage this "overriding" of the "slow_sum" function with the "fast_sum" function?

Here is a simplified example of such functions (just to illustrate):

############################

##############
# Functions in package A

slow_sum <- function(x) {
sum_x <- 0
for(i in seq_along(x)) sum_x <- sum_x + x[i]
 sum_x
}

sum_twice <- function(x) {
x2 <- rep(x,2)
slow_sum(x2)
}

##############
# A function in package B
fast_sum <- function(x) { sum(x) }

############################

If I only do something like slow_sum <- fast_sum, this would not work, since "sum_twice" uses "slow_sum" from the NAMESPACE of package A.

I tried using the following function when loading package "B":

assignInNamespace(x = "slow_sum", value = B:::fast_sum, ns = "A")

This indeed works, however, it makes the CRAN checks return both a NOTE on how I should not use ":::", and also a warning for using assignInNamespace (since it is supposed to not be very safe).

However, I am at a loss. What would be a way to have "sum_twice" use "fast_sum" instead of "slow_sum"?

Thank you upfront for any feedback or suggestion, With regards, Tal

p.s: this is a double post from here.

UDPATE: motivation for this question

I am developing two packages, one is based solely on R and works fine (but a bit slow), it is dendextend (which is now on CRAN). The other one is meant to speed up the first package by using Rcpp (this is dendextendRcpp which is on github). The second package speeds up the first by overriding some basic functions the first package uses. But in order for the higher levels functions in the first package will use the lower functions in the second package, I have to use assignInNamespace which leads CRAN to throw warnings+NOTES, which ended up having the package rejected from CRAN (until these warnings will be avoided).

The problem is that I have no idea how to approach this issue. The only solution I can think of is either mixing the two packages together (making it harder to maintain, and will automatically require a larger dependency structure for people asking to use the package). And the other option is to just copy paste the higher level functions from dendextend to dendextendRcpp, and thus have them mask the other functions. But I find this to be MUCH less elegant (because that means I will need to copy-paste MANY functions, forcing more double-code maintenance) . Any other ideas? Thanks.

Upvotes: 3

Views: 530

Answers (2)

Tal Galili
Tal Galili

Reputation: 25326

The solution I ended up using (thanks to Uwe and Kurt), is using "local" to create a localized environment with the package options. If you're curious, the function is called "dendextend_options", and is here: https://github.com/talgalili/dendextend/blob/master/R/zzz.r

Here is an example for its use:

dendextend_options <- local({
   options <- list()
   function(option, value) {
      #          ellipsis <- list(...)         
      if(missing(option)) return(options)

      if(missing(value))
         options[[option]]
      else options[[option]] <<- value
   }
})
 dendextend_options("a")
 dendextend_options("a", 1)
 dendextend_options("a")
 dendextend_options("a", NULL)
 dendextend_options("a")
 dendextend_options()

Upvotes: 2

G. Grothendieck
G. Grothendieck

Reputation: 269644

We could put this in sum_twice:

my_sum_ch <- getOption("my_sum", if ("package:fastpkg" %in% search()) 
                       "fast_sum" else "slow_sum")
my_sum <- match.fun(my_sum_ch)

If the "my_sum" option were set then that version of my_sum would be used and if not it would make the decision based on whether or not fastpkg had been loaded.

Upvotes: 2

Related Questions