同样在另一个包中设置时,S4方法也会失败

时间:2018-06-20 16:00:24

标签: r s4

当我尝试设置在另一个包中定义的方法时,我遇到了一个奇怪的问题。可以找到here来演示此问题的示例程序包。

关键是我尝试设置的typeof方法。我将setMethod函数用于typeof,并且在构建软件包并在普通的S4类上尝试时可以使用。

x <- new("A", x = 2)
typeof(x)
[1] "typeof was called"
[1] "myClassA"

但是,如果在加载typeof包之前加载另一个先前也设置了s4test的包(例如bigmemory),则直接调用它仍可以正常工作。

library(bigmemory)
library(s4test)
x <- new("A", x = 2)
typeof(x)
[1] "typeof was called"
[1] "myClassA"

但是,如果typeof方法是由另一种方法在内部调用的(例如nrow参见here),则它将失败,并且仅返回S4

nrow(x)
[1] "A"
attr(,"package")
[1] "s4test"
Function: typeof (package base)
x="ANY"
x="big.matrix"
x="myClass"

A connection with                      
description "stdout"  
class       "terminal"
mode        "w"       
text        "text"    
opened      "opened"  
can read    "no"      
can write   "yes"     
[1] "S4"

2 个答案:

答案 0 :(得分:2)

胡安·安东尼奥走在正确的轨道上, 但这与DependsImports无关。

答案在Methods_for_Nongenerics的文档条目中 (这适用于typeof,因为它不是base中的通用函数):

  

在为R包编写方法时,通常将这些方法应用于该包中不通用的函数(在另一个包中);也就是说,尽管它可能具有S3方法,但在其自己的程序包中没有用于该功能的形式方法。在这种情况下,编程涉及一个额外的步骤,即调用setGeneric()来声明该函数在您的程序包中是通用的。

     

然后,对包中的函数的调用将使用在此包中定义的所有方法,或使用任何其他已加载的创建相同泛型函数的包中的方法。同样,在这些包中调用该函数将使用您的方法。

     

但是,原始版本仍然是非通用的。除非有特殊情况,否则该软件包或使用该版本的其他软件包中的调用将调度您的方法...

您可以通过在干净的R会话中运行以下命令来查看此操作的效果:

environment(typeof)
<environment: namespace:base>

library(s4test)
environment(typeof)
<environment: 0x0000000017ca5e58>

加载软件包后, typeof函数已成为通用函数, 但不在其原始环境中。 您还可以看到新泛型环境的封闭环境

parent.env(environment(typeof))
<environment: namespace:base>

在调用函数时, R首先看一下当前环境, 并在找不到任何东西的情况下查看封闭环境。 nrow函数是base包的一部分 (它也不是通用的, 虽然在这里不相关), 这意味着它将在看到通用typeof之前找到自己的非通用Methods_for_Nongenerics

setMethod('nrow', signature(x="myClass"), function(x) { # find the generic version from the global environment and bind it here typeof <- get("typeof", .GlobalEnv) switch(typeof(x), "myClassA" = "A rows", "myClassB" = "B rows") } ) nrow(x) [1] "typeof was called" [1] "A rows" 的文档介绍了不同的情况, 但就您而言 您实际上可以执行以下操作:

<button class="subform add" onclick="addSubform(stuff); return false;" ...></button>

答案 1 :(得分:0)

问题是Depends并不总是确定的。 Imports比使用Depends更安全,您可以详细了解here

在全球环境中,您的软件包使用bigmemory :: typeof,并在nrow base :: typeof内部使用。

> base::typeof(x)
[1] "S4"
> bigmemory::typeof(x)
[1] "typeof was called"
[1] "myClassA"

您可以通过直接引用要使用的软件包名称的函数来解决此问题。