首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >S4类调度行为的不一致性

S4类调度行为的不一致性
EN

Stack Overflow用户
提问于 2014-12-09 17:11:59
回答 1查看 318关注 0票数 4

实际问题

  1. https://github.com/wch/R6类继承自(非正式的S3)类R6这一事实不应该允许为该类的签名参数定义S4方法吗?
  2. 尽管如此- AFAICT -情况并非如此,在这种情况下,有什么解决办法符合目前的S3/S4标准或多少可以被视为“最佳做法”?

背景和实例

引用类

考虑下面的示例,您希望定义在所有https://stat.ethz.ch/R-manual/R-devel/library/methods/html/refClass.html实例从(envRefClass)继承的超类上调度的方法:

代码语言:javascript
复制
TestRefClass <- setRefClass("TestRefClass", fields= list(.x = "numeric"))
setGeneric("foo", signature = "x",
  def = function(x) standardGeneric("foo")
)
setMethod("foo", c(x = "envRefClass"),
  definition = function(x) {
    "I'm the method for `envRefClass`"
})
> try(foo(x = TestRefClass$new()))
[1] "I'm the method for `envRefClass`"

这种继承结构并不明显,因为class()不会揭示这一事实:

代码语言:javascript
复制
class(TestRefClass$new())
[1] "TestRefClass"
attr(,"package")
[1] ".GlobalEnv"

但是,看看类生成器对象的属性就会发现:

代码语言:javascript
复制
> attributes(TestRefClass)
[... omitted ...]

 Reference Superclasses:  
    "envRefClass"

[... omitted ...]

这就是为什么调度工作的原因

R6类

当您想对R6类做类似的事情时,事情似乎并不直接,即使它们最初看起来是这样的(与引用类相比):

代码语言:javascript
复制
TestR6 <- R6Class("TestR6", public = list(.x = "numeric"))
setMethod("foo", c(x = "R6"),
  definition = function(x) {
    "I'm the method for `R6`"
})
> try(foo(x = TestR6$new()))
Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘foo’ for signature ‘"TestR6"’

通过“直接出现”,我的意思是class()实际上建议所有R6类继承可用作方法分派的超类的类R6

代码语言:javascript
复制
class(TestR6$new())
[1] "TestR6" "R6"  

R6Class()的帮助页面实际上显示,类R6只是作为一个非正式的S3类添加,就像class = TRUE一样。这也是为什么在试图为该类定义S4方法时会出现警告。

因此,这基本上给我们留下了两种可能的选择/解决办法:

  1. 通过R6将类setOldClass()转换为正式类
  2. 让R6类的所有实例继承其他超类,例如,.R6

( Ad 1)

代码语言:javascript
复制
setOldClass("R6")
> isClass("R6")
[1] TRUE

当侵入类表/图中的S3样式时,这是可行的:

代码语言:javascript
复制
dummy <- structure("something", class = "R6")
> foo(dummy)
[1] "I'm the method for `R6`"

但是,对于实际的R6类实例,它失败了:

代码语言:javascript
复制
> try(foo(x = TestR6$new()))
Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘foo’ for signature ‘"TestR6"’

(第二章)

代码语言:javascript
复制
.R6 <- R6Class(".R6")
TestR6_2 <- R6Class("TestR6_2", inherit = .R6, public = list(.x = "numeric"))
setMethod("foo", c(x = ".R6"),
  definition = function(x) {
    "I'm the method for `.R6`"
})
> try(foo(x = TestR6_2$new()))
Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘foo’ for signature ‘"TestR6_2"’

结论

虽然方法1排序在一个“灰色区域”中操作,以使S3和S4在某种程度上兼容,但方法2似乎是一个完全有效的“纯S4”解决方案,海事组织应该能够工作。事实上,这并没有让我提出一个问题:在R6类的实现中,在非正式/正式类和方法分派的交互方面是否存在不一致。

EN

回答 1

Stack Overflow用户

发布于 2014-12-09 17:52:11

由于Hadley Wickham,我发现setOldClass()在包含继承结构时实际上解决了这个问题:

代码语言:javascript
复制
require("R6")
setOldClass(c("TestR6", "R6"))
TestR6 <- R6Class("TestR6", public = list(.x = "numeric"))
setGeneric("foo", signature = "x",
  def = function(x) standardGeneric("foo")
)
setMethod("foo", c(x = "R6"),
  definition = function(x) {
    "I'm the method for `R6`"
  })
try(foo(x = TestR6$new()))

但是,AFAICT,这意味着对于您的包,您需要确保对您希望使用setOldClass()方法的所有R6类都以这种方式调用S4。

这可以通过在函数.onLoad().onAttach()中绑定这些调用来实现(参见here):

代码语言:javascript
复制
.onLoad <- function(libname, pkgname) {
  setOldClass(c("TestR6_1", "R6"))
  setOldClass(c("TestR6_2", "R6"))
  setOldClass(c("TestR6_3", "R6"))
}

这是假设您已经定义了三个R6类(TestR6_1通过TestR6_3)

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27384772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档