S4クラスを継承する時に気を付けること
背景
S4クラスメカニズムでは、setMethod関数のcontains引数に親クラスの名前を含める事で継承を実現できる。で、こんなコードを書くとエラーになってしまった。
setClass("A", representation(a="numeric")) setMethod("initialize", "A", function(.Object, a){ .Object@a <- a .Object }) setClass("B", representation(b="numeric"), contains="A") # => Error in .local(.Object, ...) : argument "a" is missing, with no default
取り敢えずの解決策
こういう事をしたければ
setClass("A", representation(a="numeric")) setMethod("initialize", "A", function(.Object, ...){ args <- list(...) if(!is.null(args$a)) .Object@a <- args$a .Object }) setClass("B", representation(b="numeric"), contains="A")
こう書くのが筋であるっぽい。ポイントは、
- S4クラスのinitialize関数の引数は(.Object, ...)という形式が標準的
- 常にnew("ClassName")という式が評価出来るべき
という所。
これを守らないと色んな所でコケてしまうらしい。何でこういう風になっているのか、に関しては全く不明。参考ページへ
ついでに親クラスのコンストラクタの呼び方
子クラスの initialize 時に親クラスの initialize を呼ぶには callNextMethod を使う。
setMethod("initialize", "B", function(.Object, ...){ args <- list(...) if(!is.null(args$b)) .Object@b <- args$b callNextMethod() }) new("B", a=1, b=2) ## An object of class "B" ## Slot "b": ## [1] 2 ## Slot "a": ## [1] 1