Extent S4 class, how to use superclass' constructor

Tag: r , s4 Author: liming010203 Date: 2013-04-24

In my package, I want to subclass a class TheBaseClass from a contributed package (so it is out of my reach). There is a function for creating objects of this class. Here is a minimal example for that code.

setClass("TheBaseClass", representation(a="numeric"))
initBase <- function() new("TheBaseClass", a=1)  # in reality more complex

Now I want simply use initBase as constructor for my subclass, but I do not know how to set the new class

setClass("MyInheritedClass", contains="TheBaseClass")
initInher <- function() {
    res <- initBase()
    class(res) <- "MyInheritedClass" # this does not work for S4
}

How can I alter the last line to make it work? Copy & paste the initBase function is not an option, since it involves a .C call. I read about setIs, but this seems not to be the right function here.

Any hint appreciated!

Best Answer

Perhaps this answer provides more extensive explanation. One pattern is to provide an instance of the base class as an unnamed argument to your class constructor

.MyInheritedClass <- setClass("MyInheritedClass", contains="TheBaseClass")
.MyInheritedClass(initBase())

(setClass returns a generator function, which is really no different from calling new but seems cleaner; I use . in front, because generators are maybe a little too crude for "end users", e.g., there is no hint about what the arguments are supposed to be, just ...). This assumes that you have not written an initialize method for your class, or that your initialize method has been constructed in a way that is consistent with the contract of initialize,ANY-method, with a slightly more complicated class

.A <- setClass("A", contains="TheBaseClass",
    representation=representation(x="numeric"))

setMethod(initialize, "A",
   function(.Object, ..., x)
{
    x <- log(x)                          # your class-specific initialization...
    callNextMethod(.Object, ..., x = x)  # passed to parent constructor
})

This pattern requires that the initialize method of the base class has been designed correctly. In action:

> .A(initBase(), x=1:2)
An object of class "A"
Slot "x":
[1] 0.0000000 0.6931472

Slot "a":
numeric(0)

comments:

this is really helpful; also the answer you linked to, which I did not find before. Thanks!