混合 S3 和 S4 时的方法调度
Method dispatch when mixing S3 and S4
我想了解 R 在混合 S3 和 S4 时为找到合适的函数所经历的步骤。这是一个例子:
set.seed(1)
d <- data.frame(a=rep(c('a', 'b'), each=15),
b=rep(c('x', 'y', 'z'), times=5),
y=rnorm(30))
m <- lme4::lmer(y ~ b + (1|a), data=d)
l <- lsmeans::lsmeans(m, 'b')
multcomp::cld(l)
我不完全理解执行最后一行时会发生什么。
multcomp::cld
打印 UseMethod("cld")
,因此 S3 方法调度。
isS4(l)
表明 l
是 S4 class 对象。
似乎尽管调用了 S3 泛型,但 S3 调度系统被完全忽略了。创建函数 print.lsmobj <- function(obj) print('S3')
(因为 class(l)
是 lsmobj
)和 运行 cld(l)
不打印 "S3"
.
showMethods(lsmobj)
或 showMethods(ref.grid)
(超级 class),不要列出任何类似于 cld
函数的内容。
使用debugonce(multcomp::cld)
表明最终调用的函数是cld.ref.grid
from lsmeans
.
不过,我想知道如何实现 cld.ref.grid
最终会像 debugonce
一样在没有任何 "tricks" 的情况下被调用。也就是说,R 执行哪些步骤才能到达 cld.ref.grid
.
为了注册 S3 方法,泛型必须可用。在这里,我为 merMod
个对象编写了一个简单的 foo
方法:
> library(lme4)
> foo.merMod = function(object, ...) { "foo" }
> showMethods(class = "merMod")
Function ".DollarNames":
<not an S4 generic function>
Function "complete":
<not an S4 generic function>
Function "formals<-":
<not an S4 generic function>
Function "functions":
<not an S4 generic function>
Function: getL (package lme4)
x="merMod"
Function "prompt":
<not an S4 generic function>
Function: show (package methods)
object="merMod"
> methods(class = "merMod")
[1] anova as.function coef confint cooks.distance
[6] deviance df.residual drop1 extractAIC family
[11] fitted fixef formula getL getME
[16] hatvalues influence isGLMM isLMM isNLMM
[21] isREML logLik model.frame model.matrix ngrps
[26] nobs plot predict print profile
[31] ranef refit refitML rePCA residuals
[36] rstudent show sigma simulate summary
[41] terms update VarCorr vcov weights
两个列表都不包含 foo
。但是如果我们定义泛型,那么它会出现在 methods()
结果中:
> foo = function(object, ...) UseMethod("foo")
> methods(class = "merMod")
[1] anova as.function coef confint cooks.distance
[6] deviance df.residual drop1 extractAIC family
[11] fitted fixef foo formula getL
[16] getME hatvalues influence isGLMM isLMM
[21] isNLMM isREML logLik model.frame model.matrix
[26] ngrps nobs plot predict print
[31] profile ranef refit refitML rePCA
[36] residuals rstudent show sigma simulate
[41] summary terms update VarCorr vcov
[46] weights
现在包括foo
同样,在您的示例中,如果您执行 library(multcomp)
,methods()
将显示 cld
的存在,因为那是 cld
的泛型所在的位置。
较旧的 R 文档(2016 年之前)过去包含比当前文档更多的详细信息,但粗略地说,该过程按优先级降序排列如下:
1) 如果函数是标准的 S4 泛型并且签名中的任何参数都是 S4(根据 isS4
),则根据通常的规则选择最佳的 S4 方法。
2) 如果函数是一个非标准的 S4 泛型,那么它的主体将被执行,然后在某个时候调用 S4 调度本身。
3) 如果函数是 S3 通用函数,则 S3 分派发生在第一个参数上(内部通用二元运算符除外)。
4) 如果该函数根本不是泛型的,那么它会以通常的方式对其所有参数进行惰性求值。
请注意,来自 setGeneric
的帮助页面:
"Functions that dispatch S3 methods by calling UseMethod
are ordinary functions, not objects from the "genericFunction"
class. They are made generic like any other function, but some special considerations apply to ensure that S4 and S3 method dispatch is consistent (see Methods_for_S3)."
我想了解 R 在混合 S3 和 S4 时为找到合适的函数所经历的步骤。这是一个例子:
set.seed(1)
d <- data.frame(a=rep(c('a', 'b'), each=15),
b=rep(c('x', 'y', 'z'), times=5),
y=rnorm(30))
m <- lme4::lmer(y ~ b + (1|a), data=d)
l <- lsmeans::lsmeans(m, 'b')
multcomp::cld(l)
我不完全理解执行最后一行时会发生什么。
multcomp::cld
打印 UseMethod("cld")
,因此 S3 方法调度。
isS4(l)
表明 l
是 S4 class 对象。
似乎尽管调用了 S3 泛型,但 S3 调度系统被完全忽略了。创建函数 print.lsmobj <- function(obj) print('S3')
(因为 class(l)
是 lsmobj
)和 运行 cld(l)
不打印 "S3"
.
showMethods(lsmobj)
或 showMethods(ref.grid)
(超级 class),不要列出任何类似于 cld
函数的内容。
使用debugonce(multcomp::cld)
表明最终调用的函数是cld.ref.grid
from lsmeans
.
不过,我想知道如何实现 cld.ref.grid
最终会像 debugonce
一样在没有任何 "tricks" 的情况下被调用。也就是说,R 执行哪些步骤才能到达 cld.ref.grid
.
为了注册 S3 方法,泛型必须可用。在这里,我为 merMod
个对象编写了一个简单的 foo
方法:
> library(lme4)
> foo.merMod = function(object, ...) { "foo" }
> showMethods(class = "merMod")
Function ".DollarNames":
<not an S4 generic function>
Function "complete":
<not an S4 generic function>
Function "formals<-":
<not an S4 generic function>
Function "functions":
<not an S4 generic function>
Function: getL (package lme4)
x="merMod"
Function "prompt":
<not an S4 generic function>
Function: show (package methods)
object="merMod"
> methods(class = "merMod")
[1] anova as.function coef confint cooks.distance
[6] deviance df.residual drop1 extractAIC family
[11] fitted fixef formula getL getME
[16] hatvalues influence isGLMM isLMM isNLMM
[21] isREML logLik model.frame model.matrix ngrps
[26] nobs plot predict print profile
[31] ranef refit refitML rePCA residuals
[36] rstudent show sigma simulate summary
[41] terms update VarCorr vcov weights
两个列表都不包含 foo
。但是如果我们定义泛型,那么它会出现在 methods()
结果中:
> foo = function(object, ...) UseMethod("foo")
> methods(class = "merMod")
[1] anova as.function coef confint cooks.distance
[6] deviance df.residual drop1 extractAIC family
[11] fitted fixef foo formula getL
[16] getME hatvalues influence isGLMM isLMM
[21] isNLMM isREML logLik model.frame model.matrix
[26] ngrps nobs plot predict print
[31] profile ranef refit refitML rePCA
[36] residuals rstudent show sigma simulate
[41] summary terms update VarCorr vcov
[46] weights
现在包括foo
同样,在您的示例中,如果您执行 library(multcomp)
,methods()
将显示 cld
的存在,因为那是 cld
的泛型所在的位置。
较旧的 R 文档(2016 年之前)过去包含比当前文档更多的详细信息,但粗略地说,该过程按优先级降序排列如下:
1) 如果函数是标准的 S4 泛型并且签名中的任何参数都是 S4(根据 isS4
),则根据通常的规则选择最佳的 S4 方法。
2) 如果函数是一个非标准的 S4 泛型,那么它的主体将被执行,然后在某个时候调用 S4 调度本身。
3) 如果函数是 S3 通用函数,则 S3 分派发生在第一个参数上(内部通用二元运算符除外)。
4) 如果该函数根本不是泛型的,那么它会以通常的方式对其所有参数进行惰性求值。
请注意,来自 setGeneric
的帮助页面:
"Functions that dispatch S3 methods by calling UseMethod
are ordinary functions, not objects from the "genericFunction"
class. They are made generic like any other function, but some special considerations apply to ensure that S4 and S3 method dispatch is consistent (see Methods_for_S3)."