Is there a way to initialize a S4 object so that another object will be returned?
I have a class hierarchy with the superclass fb
of which no objects should exist (I tried virtual classes but ran in the problem that you can not initialize objects from virtual classes). Further, I have two sub classes (foo
, bar
) with the same slots. Now I want to make a new object, using an initialize method to the superclass that returns an object of one of the subclasses based on some value:
setClass("fb"开发者_运维问答, representation( x = "numeric"))
setClass("foo", contains = "fb")
setClass("bar", contains = "fb")
setMethod("initialize", "fb", function(.Object, x) {
if (x < 5) class(.Object) <- "foo"
else class(.Object) <- "bar"
.Object@x <- x
.Object
})
> new("fb", x = 3)
Error in initialize(value, ...) :
initialize method returned an object of class "foo" instead of the required class "fb"
Obviously (and probably with good reasons) R disallows that. Is there a way to achieve what I want within a method and not using an if-else construct when I create the new object?
S4 helps us to color within the lines. So your fb
class should be virtual, your initialize
method shouldn't change the class of .Object
. You might write a function fb
that does your conditional instantiation.
setClass("fb", representation( x = "numeric", "VIRTUAL"))
setClass("foo", contains = "fb")
setClass("bar", contains = "fb")
fb <-
function(x)
{
if (x < 5) new("foo", x=x)
else new("bar", x=x)
}
fb
is a constructor, more convenient for the user, and separates the interface to your class hierarchy from its implementation which is generally considered a good thing.
And for what it's worth an implicit constraint on S4 initialize
methods is that new("foo")
(invoking new
with the class name but no additional arguments) must work (otherwise there are failures when you try to extend foo). So the paradigm for an initialize method is along the lines of
setMethod(initialize, "foo", function(.Object, ..., x=1) {
.Object <- callNextMethod(.Object, ...)
.Object@x <- x
.Object
})
though often (as in this case, where initialize
is just doing slot assignment) there is no need for an initialize method at all. Note the use of ...
, the positioning of x
(requiring that the argument be named in the corresponding call to new
) and the use of a default value.
精彩评论