片状S4方法分派

时间:2019-06-24 15:22:15

标签: r methods

我正在测试是否可以支持使用 ememans 中的 cplm 软件包拟合的模型,并且遇到了terms的一些非常奇怪的行为方法。这是一个示例:

library(emmeans)
library(cplm)

data(mtcars)

m <- cpglm(mpg ~ cyl + disp + hp, data = mtcars)

函数emmeans:::recover_data.lm似乎可以正常工作。它只是在对象上调用terms方法,并将其传递给其他函数。但是,它不起作用:

> emmeans:::recover_data.lm(m)
 Error in slot(x, name) : 
  no slot of name "terms" for this object of class "cpglm" 

进一步研究,我确认terms()在全局环境中确实有效:

> terms(m)
mpg ~ cyl + disp + hp
... (remaining lines excluded) ...

但是,它在recover_data.lm中不起作用:

> debug(emmeans:::recover_data.lm)
> emmeans:::recover_data.lm(m)
    ...

Browse[2]> terms(object)
Error in slot(x, name) : 
  no slot of name "terms" for this object of class "cpglm"

Browse[2]> getMethod("terms", "cpglm")
Error in getMethod("terms", "cpglm") : 
  no method found for function 'terms' and signature cpglm

但是...

Browse[2]> getMethod("terms", "cplm")  ## cpglm inherits from cplm
Method Definition:

function (x, ...) 
attr(x@model.frame, "terms")
    ... etc. ...

Browse[2]> methods("terms")
[1] terms,ANY-method  terms,cplm-method terms.default*    terms.formula*    terms.gls*       
[6] terms.merMod*     terms.terms*     
see '?methods' for accessing help and source code

Browse[2]> selectMethod("terms", "cpglm")
Method Definition:

function (x, ...) 
attr(x@model.frame, "terms")
    ... etc. ...

因此,在 emmeans 的名称空间中,我可以验证我们“知道” terms对象有一个cpglm方法,并且可以通过以下方式找到它selectMethod(),但不能通过getMethod()或仅通过调用terms()来实现。这很奇怪,尤其是因为selectMethod的文档似乎承诺它应该可以工作:

  

函数selectMethod()返回将被选择的方法   如果参数具有由所指定的类,则调用函数f   signature

最后,我能够验证这似乎与调度S3方法时的冲突有关:

> stats::terms(m)
Error in slot(x, name) : 
  no slot of name "terms" for this object of class "cpglm"

当S3和S4方法混合使用时,有没有办法让我的软件包 emmeans 正常工作;特别是要在S3方法之前先寻找S4方法?

1 个答案:

答案 0 :(得分:1)

来自Methods_for_S3中的文档条目:

  

同时定义S3和S4方法的原因如下:

     
      
  1. 如果直接调用S3泛型函数,则将不会单独看到S4方法。例如,如果某些函数从不使该函数成为S4泛型的程序包中调用unique(),就会是这种情况。
  2.   

cplm软件包为terms导出了S4方法, 但不是S3的一个 您可以看到here。 当您附加terms时,这将自动使cplm成为S4通用。 但是,emmeansstats调用S3泛型, 这就是导致问题的原因。

您可以通过在调度到S4泛型的全局环境中定义一个S3泛型来解决此问题:

terms.cpglm <- function(x, ...) {
    cplm::terms(x, ...)
}

但是您应该让cplm维护人员知道,如果他要将S3泛型转换为S4,则应该定义S3和S4方法。