S4とか総称的関数を使い出すとたぶんどっかでぶちあたるのがmethod dispatch問題です。僕は去年の夏くらいから「よく分からないなー」と思ってました。
method dispatchというのを間違ってるかもしれないけど、分かりやすめに説明すると、
- 総称関数が使われた(例えばplot)!!
- plot.lmとかplot.defaultとかplot.tsとかいっぱいある
- 色々型とかに合わせて使いわけるようにしたいけど、どういう風の処理させよう?
みたいなものを解決する手段のようです。
gdgd言う前に例を考えてみます。hogeというクラスを作ってみます。
> setClass("hoge", representation(x="numeric")) [1] "hoge"
このクラスにはまだplotというメソッドは用意されていないので、エラーが出ます(S4型に対するplotメソッドは未定義、というほうがいいかな)。
> plot(new("hoge",x=1:10)) 以下にエラー as.double(y) : cannot coerce type 'S4' to vector of type 'double'
なので、このクラス用のmethodを定義してやります。するとこんな感じでうまくいきます。
> setMethod("plot",signature(x="hoge",y="missing"),function(x,y,...){ + plot(slot(x,"x")) + }) 新しい総称関数 "plot" を ".GlobalEnv" 中に生成します [1] "plot" > > plot(new("hoge",x=1:10))
このhogeクラス用の関数plotを定義した後のplotはこんな感じになっています。
> plot standardGeneric for "plot" defined from package "graphics" function (x, y, ...) standardGeneric("plot") <environment: 0x199c72c> Methods may be defined for arguments: x, y Use showMethods("plot") for currently available ones.
一方、この関数を定義する前のふつーのplotはこんな感じになっています。さっきの関数を定義することで変化している、ということが分かります。
> plot function (x, y, ...) { if (is.function(x) && is.null(attr(x, "class"))) { if (missing(y)) y <- NULL hasylab <- function(...) !all(is.na(pmatch(names(list(...)), "ylab"))) if (hasylab(...)) plot.function(x, y, ...) else plot.function(x, y, ylab = paste(deparse(substitute(x)), "(x)"), ...) } else UseMethod("plot") } <environment: namespace:graphics>