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.
在包A中,我有一些函数(比如“sum_two”),它调用包中的另一个函数(比如“slow_sum”)。但是,在B包中,我编写了另一个函数(比如“fast_sum”),我希望用它来替换A包中的慢函数。
Now, how do I manage this "overriding" of the "slow_sum" function with the "fast_sum" function?
现在,我如何使用“fast_sum”函数来管理“slow_sum”函数的“override”?
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.
如果我只执行像slow_sum <- fast_sum这样的操作,那么这将不起作用,因为“sum_two”使用了包A的名称空间中的“slow_sum”。
I tried using the following function when loading package "B":
我在装载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).
然而,这确实有效,它使CRAN检查返回一个关于如何不使用“:::”的说明,以及使用assignInNamespace的警告(因为它应该不是很安全)。
However, I am at a loss. What would be a way to have "sum_twice" use "fast_sum" instead of "slow_sum"?
然而,我却不知所措。什么是“sum_two”使用“fast_sum”而不是“slow_sum”的方法?
Thank you upfront for any feedback or suggestion, With regards, Tal
首先感谢您对Tal的任何反馈或建议。
p.s: this is a double post from here.
p。s:这是从这里传过来的。
UDPATE: motivation for this question
UDPATE:这个问题的动机
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).
我正在开发两个包,一个仅基于R并且工作良好(但是有点慢),它是dendextend(现在在CRAN上)。另一种方法是使用Rcpp加速第一个包(这是在github上的dendextendRcpp)。第二个包通过重写第一个包使用的一些基本函数来加速第一个包。但是,为了让第一个包中的高级函数使用第二个包中的低级函数,我必须使用assignInNamespace,这会导致CRAN抛出警告+NOTES,最终导致该包被CRAN拒绝(直到这些警告被避免)。
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.
问题是我不知道如何处理这个问题。我能想到的唯一解决方案是将两个包混合在一起(使其更难维护,并将自动要求更大的依赖结构,以供要求使用该包的人使用)。另一种选择是复制dendextend to dendextendRcpp中的高级函数,从而使它们掩盖其他函数。但是我发现这样做不那么优雅(因为这意味着我需要复制粘贴许多函数,从而迫使进行更多的双代码维护)。任何其他想法?谢谢。
2 个解决方案
#1
2
We could put this in sum_twice
:
我们可以把这个代入sum_two:
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.
如果设置了“my_sum”选项,那么将使用my_sum的版本,如果没有,它将根据是否加载fastpkg来做出决定。
#2
1
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
我最后使用的解决方案(感谢Uwe和Kurt)是使用“local”来创建带有包选项的本地化环境。如果您好奇,这个函数被称为“dendextend_options”,它在这里: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()
#1
2
We could put this in sum_twice
:
我们可以把这个代入sum_two:
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.
如果设置了“my_sum”选项,那么将使用my_sum的版本,如果没有,它将根据是否加载fastpkg来做出决定。
#2
1
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
我最后使用的解决方案(感谢Uwe和Kurt)是使用“local”来创建带有包选项的本地化环境。如果您好奇,这个函数被称为“dendextend_options”,它在这里: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()