R 3.0.0からsetClass()
にはslots
という引数が追加され、representation
引数ではなくこちらを使うことが推奨されています。
setClass()
has a new argument,slots
, clearer and less ambiguous thanrepresentation
. 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
引数は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
引数は、各スロットのデフォルト値を指定するためのものでした。現在は、デフォルト値を指定したい場合は、初期化時に呼び出されるメソッド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
引数は、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