开发者

Is there a way to initialize a S4 object so that another object will be returned?

开发者 https://www.devze.com 2023-03-22 11:06 出处:网络
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 h

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消