Copying S4 base class instance into a derived object

五迷三道 提交于 2019-12-06 14:13:46

问题


I have two simple classes:

.A1 <- setClass("A1", 
            representation=representation( x1 ="numeric"),
            prototype = prototype(x1 = 10))

.A2 <- setClass("A2", contains="A1",
           representation=representation(x2="numeric"),
           prototype = prototype(x2 = 10))

setMethod("initialize", "A2",
      function(.Object, ..., x2 = .Object@x2)
      {
        callNextMethod(.Object, ..., x2 = x2)
      })

Using this code everything works:

a1 <- .A1(x1 = 3)
initialize(a1)

a2 <- .A2(x1 = 2, x2 = 4)
initialize(a2, x2 = 3)

.A2(a1, x2 = 2)

An object of class "A2"  # WORKS!
Slot "x2":
[1] 2

Slot "x1":
[1] 3

In particular the last line work, so a1 gets copied inside the "A2" object. The problem is that if define "initialize" also for the base class the last line doesn't work anymore:

setMethod("initialize", "A1",
      function(.Object, ..., x1 = .Object@x1)
      {
        callNextMethod(.Object, ..., x1 = x1)
      })

## I have to redefine also this initializer, otherwise it will call
## the default initializer for "A1" (it was stored in some lookup table?)
setMethod("initialize", "A2",
      function(.Object, ..., x2 = .Object@x2)
      {
        # your class-specific initialization...passed to parent constructor
        callNextMethod(.Object, ..., x2 = x2)
      })

And now I get:

.A2(a1, x2 = 2)
An object of class "A2"  # BAD!
Slot "x2":
[1] 2

Slot "x1":
[1] 10

I guess there is something wrong with my initializer of "A1", any ideas? Thanks!


回答1:


The A1 initialize method mis-behaves because x1 = .Object@x1 consults .Object, which for the constructor is the prototype of the class (for your example .A2(a1, x2=2), in the initialize,A1-method .Object is constructed from the prototype of A2, so x1 is assigned 10, and x1 = .Object@x1 = 10 over-writes the value provided by a1.

It's hard to know what a general solution is. You could test for missing-ness

setMethod("initialize", "A1", function(.Object, ..., x1) {
    if (!missing(x1))
        callNextMethod(.Object, ..., x1=x1)
    else 
        callNextMethod(.Object, ...)
})

or do something clever, maybe with match.call, to avoid a combinatorial problem with more than a couple of slots.

Another approach, which seems to be the one adopted in practice even though it really just side-steps the problem, is to avoid using an initialize method, and instead rely on a separate constructor to do any data massaging, as in the first code box of the Retaining copy construction section of this answer.



来源:https://stackoverflow.com/questions/18249845/copying-s4-base-class-instance-into-a-derived-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!