実際の質問
R6クラスが (非公式の S3) クラスから継承するという事実
R6
は、まさにそのクラスの署名引数の S4 メソッドの定義を許可するべきではないでしょうか?これは - AFAICT - そうではないので、現在の S3/S4 標準に沿った回避策、またはそのような状況で「ベストプラクティス」と見なすことができる回避策は何ですか?
背景と例
参照クラス
参照クラスのすべてのインスタンスが継承するスーパークラス ( envRefClass
)でディスパッチするメソッドを定義する次の例を考えてみます。
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()
この継承構造は、その事実を明らかにしないため、直接明らかではありません。
class(TestRefClass$new())
[1] "TestRefClass"
attr(,"package")
[1] ".GlobalEnv"
ただし、クラス ジェネレーター オブジェクトの属性を見ると、次のことがわかります。
> attributes(TestRefClass)
[... omitted ...]
Reference Superclasses:
"envRefClass"
[... omitted ...]
だからディスパッチは機能する
R6 クラス
R6 クラスに同様のことをしたい場合、(参照クラスと比較して) 最初はそのように見えても、物事は単純ではないように見えます。
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"’
「単純に見える」とは、すべての R6 クラスが、メソッド ディスパッチのスーパークラスとして使用できるclass()
クラスから継承することを実際に示唆していることを意味します。R6
class(TestR6$new())
[1] "TestR6" "R6"
のヘルプ ページでR6Class()
は、クラスR6
がclass = TRUE
. これが、このクラスの S4 メソッドを定義しようとすると警告が表示される理由でもあります。
したがって、これにより、基本的に2つの可能なオプション/回避策が残ります。
- クラス
R6
を正式なクラスに変えるsetOldClass()
- R6 クラスのすべてのインスタンスを他のスーパークラスから継承させます。たとえば、
.R6
広告 1)
setOldClass("R6")
> isClass("R6")
[1] TRUE
これは、クラス テーブル/グラフで S3 スタイルをハッキングするときに機能します。
dummy <- structure("something", class = "R6")
> foo(dummy)
[1] "I'm the method for `R6`"
ただし、実際の R6 クラス インスタンスでは失敗します。
> try(foo(x = TestR6$new()))
Error in (function (classes, fdef, mtable) :
unable to find an inherited method for function ‘foo’ for signature ‘"TestR6"’
広告 2)
.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 は、IMO が機能する完全に有効な「純粋な S4」ソリューションのように見えます。Rでの非公式/公式クラスとメソッドディスパッチの相互作用に関して、R6クラスの実装に矛盾があるかどうかという問題を提起することにはならなかったという事実.