Class slots vs. initialize signature mismatch

2019-05-30 20:41发布

问题:

Consider the following S4 class:

setClass('Foo', representation(model='data.frame'))

setMethod('initialize', 'Foo',
      function(.Object, a, b) {
        .Object@model <- data.frame(a, b)
        .Object
      })

It can be instantiated with:

new('Foo', a=1:4, b=4:7)

So far so good. However, when I try to subclass Foo I get an error.

setClass('Bar', contains='Foo')
>>> Error in data.frame(a, b) : argument "a" is missing, with no default

Personally, I would prefer to instantiate class Foo with explicit arguments because the code is more... well, explicit. However, this does not seem possible, does it? It looks like the signature of initialize must match the slots that the class has, otherwise it's a problem waiting to happen. Am I wrong?

回答1:

The requirement is that new called with no arguments, new("Foo"), must work. Also, it's probably better practice for your initialize method to take ..., to callNextMethod, and to have arguments after the ... (because initialize is documented to use unnamed arguments for initializing contained classes). So

setMethod(initialize, "Foo", function(.Object, ..., a=integer(), b=integer()) {
    callNextMethod(.Object, ..., model=data.frame(a, b))
})

Normally one wants to insulate the user from calling new, and will instead use a constructor Foo. Typically the constructor does whatever coercion you might have instead put in the initialize method, so the initialize method is just not specified.

Foo <- function(a=integer(), b=integer(), ...) {
    model <- data.frame(a, b)
    new("Foo", model=model, ...)
}


标签: oop r s4