initialize メソッドの挙動 を調べていたら、R devel の ML (Ref Classes: bug with using '.self' within initialize methods?) と TractoR というパッケージのコードを見つけ、これを参考に uninitializedField に初期値を与えてみるコードを書きました。
myclass0 <- setRefClass( Class = "myclass0", fields = c("field1"), methods = list( initialize = function(...) { object <- initFields(...) print(initFields) if (class(object$field1) == "uninitializedField") object$field1 <- 5 return(object) }, myfunc0 = function(a) { a - field1 } ) ) myclass1 <- setRefClass( Class = "myclass1", fields = c("field1"), methods = list( initialize = function(...) { object <- callSuper(...) print(callSuper) if (class(object$field1) == "uninitializedField") object$field1 <- 5 return(object) }, myfunc0 = function(a) { a - field1 } ) ) test0 <- myclass0$new() test0$myfunc0(5) test1 <- myclass1$new() test1$myfunc0(5) test0 <- myclass0$new(field1 = 10) test0$myfunc0(5)
ここで、myclass0 の initialize では initFields(...) を呼び出していて、myclass1 の initialize では callSuper(...) を呼んでいるという違いがあります。
これらを実行してみると、
> test0 <- myclass0$new() function (...) { if (length(list(...)) > 0) initFieldArgs(.self, .refClassDef, as.environment(.self), ...) else .self } <environment: 0x0566f5c4> attr(,"mayCall") character(0) attr(,"name") [1] "initFields" attr(,"refClassName") [1] "envRefClass" attr(,"superClassMethod") [1] "" attr(,"class") [1] "refMethodDef" attr(,"class")attr(,"package") [1] "methods"
> test1 <- myclass1$new() function (...) { if (length(list(...)) > 0) initFieldArgs(.self, .refClassDef, as.environment(.self), ...) else .self } <environment: 0x05760468> attr(,"mayCall") character(0) attr(,"name") [1] "initFields" attr(,"refClassName") [1] "envRefClass" attr(,"superClassMethod") [1] "" attr(,"class") [1] "refMethodDef" attr(,"class")attr(,"package")
となって、あぁやっぱり initialize 中の callSuper(...) は initFields(...) を呼んでいるんだなぁという事が分かりました確認できました。
methods pacakge のソースを読めばいいのですが、読んでもよく分からなかったので・・・
# refClass.R - Lines 162-177 ## assign references to the object and to its class definition assign(".self", .Object, envir = selfEnv) assign(".refClassDef", classDef, envir = selfEnv) if(is.function(classDef@refMethods$finalize)) reg.finalizer(selfEnv, function(x) x$.self$finalize()) if(is.function(classDef@refMethods$initialize)) .Object$initialize(...) else { if(nargs() > 1) { .Object <- methods::initFieldArgs(.Object, classDef, selfEnv, ...) ## reassign in case something changed assign(".self", .Object, envir = selfEnv) } .Object }
実行結果はこんな感じでした。
> test0 <- myclass0$new() > test0$myfunc0(5) [1] 0 > test1 <- myclass1$new() > test1$myfunc0(5) [1] 0 > test0 <- myclass0$new(field1 = 10) > test0$myfunc0(5) [1] -5