Skip to content

Latest commit

 

History

History
158 lines (120 loc) · 5.16 KB

File metadata and controls

158 lines (120 loc) · 5.16 KB

R 3.0.0以降のS4クラスの定義方法

R 3.0.0からsetClass()にはslotsという引数が追加され、representation引数ではなくこちらを使うことが推奨されています。

setClass() has a new argument, slots, clearer and less ambiguous than representation. It is recommended for future code, but should be back-compatible. At the same time, the allowed slot specification is slightly more general. See the documentation for details. (https://cran.r-project.org/bin/windows/base/old/3.0.0/NEWS.R-3.0.0.html)

また、prototype引数やvalidity引数についても別の手段が推奨されています。

These arguments are currently allowed, but either they are unlikely to be useful or there are modern alternatives that are preferred. (?setClass, https://stat.ethz.ch/R-manual/R-devel/library/methods/html/setClass.html)

representation

representation引数はS4クラスのスロットを指定するものでした。これはslots引数で完全に代替でき、representation()の代わりに名前付きベクトルを指定します。

具体的には、古い書き方だと以下ようなクラス定義だったものは、

setClass("ClassA_deprecated",
         representation = representation(slotA = "character",
                                         slotB = "numeric"))

以下のように書くことが推奨されます。

setClass("ClassA",
         slots = c(slotA = "character",
                   slotB = "numeric"))

showClass()を使うと、いずれも同じ定義になっていることが確認できます。

showClass("ClassA_deprecated")
#> Class "ClassA_deprecated" [in ".GlobalEnv"]
#> 
#> Slots:
#>                           
#> Name:      slotA     slotB
#> Class: character   numeric


showClass("ClassA")
#> Class "ClassA" [in ".GlobalEnv"]
#> 
#> Slots:
#>                           
#> Name:      slotA     slotB
#> Class: character   numeric

prototype

prototype引数は、各スロットのデフォルト値を指定するためのものでした。現在は、デフォルト値を指定したい場合は、初期化時に呼び出されるメソッドinitialize()を実装してその中に初期化処理を入れる、というやり方が推奨されています。

具体的には、古い書き方だと以下のようなクラス定義だったものは、

setClass("ClassB_deprecated",
         representation = representation(slotA = "character",
                                         slotB = "numeric"),
         prototype = prototype(slotA = "DEFAULT",
                               slotB = pi))

以下のようにメソッドを定義します。callNextMethod()でデフォルトのinitialize()メソッドを呼んでおかないと、次に説明するバリデーション等の処理が行われないので注意しましょう。

setClass("ClassB",
         slots = c(slotA = "character",
                   slotB = "numeric"))

setMethod("initialize", signature = "ClassB",
          function(.Object, slotA = "DEFAULT", slotB = pi) {
            .Object <- callNextMethod()
            .Object@slotA <- slotA
            .Object@slotB <- slotB
            .Object
          })
#> [1] "initialize"

やや冗長にはなりますが、単純なデフォルト引数の処理だけでなく、様々な初期化処理を自由に指定できるのが利点でしょう。

new()で新しいインスタンスを作ってみると、以下のように同じ値になっていることがわかります。

new("ClassB_deprecated")
#> An object of class "ClassB_deprecated"
#> Slot "slotA":
#> [1] "DEFAULT"
#> 
#> Slot "slotB":
#> [1] 3.141593


new("ClassB")
#> An object of class "ClassB"
#> Slot "slotA":
#> [1] "DEFAULT"
#> 
#> Slot "slotB":
#> [1] 3.141593

validity

validity引数は、S4クラスのインスタンス作成時に行うバリデーションを指定するためのものでした。setValidity()を代わりにに使うことが推奨されています。

具体的には、以下のようにクラス定義をしていたものは

is_valid_classC <- function(object) {
  if (object@slotB >= 0) {
    TRUE 
  } else {
    "slotB is negative"
  }
}

setClass("ClassC_deprecated",
         representation = representation(slotA = "character",
                                         slotB = "numeric"),
         validity = is_valid_classC)

クラス定義のあとでsetValidity()を指定します。

setClass("ClassC",
         slots = c(slotA = "character",
                   slotB = "numeric"))
setValidity("ClassC", is_valid_classC)
#> Class "ClassC" [in ".GlobalEnv"]
#> 
#> Slots:
#>                           
#> Name:      slotA     slotB
#> Class: character   numeric

いずれも、以下のようにエラーになることが確認できるでしょう。

new("ClassC_deprecated", slotB = -1)
#> Error in validObject(.Object): invalid class "ClassC_deprecated" object: slotB is negative


new("ClassC", slotB = -1)
#> Error in validObject(.Object): invalid class "ClassC" object: slotB is negative