alexwhitworth
alexwhitworth

Reputation: 4907

properly specify S4 generics

Sorry for my ignorance, but I do not understand how to properly implement S4 generics. I've been struggling for the past few hours. Hopefully it's a simple fix.

I'm trying to define simple methods such as print and summary for my class. I've tried a bunch of different variations to the below. What is below seems to be the closest thing to working but still clearly not proper.

What is the proper way to do this? What am I doing wrong?

setClass("foo",
         representation= list(method= "character",
                              mle_iter= "numeric",
                              mle_log_lik= "numeric",
                              data= "list"))


print.foo <- function(obj) {
  cat("\n Method: ", obj@method,
      "\n\n Iterations: ", obj@mle_iter,
      "\n\n Log-Likelihood: ", obj@mle_log_lik)
}

setGeneric("print",
           def= function(obj) {
             print.foo(obj)
             standardGeneric("print")
           })

setMethod("print", signature= "foo",
          function(obj) {
            print(obj)
          })


dat <- as.data.frame(matrix(rnorm(500), ncol=5))

foo1 <- new("foo",
           method= "EM",
           mle_iter= 6,
           mle_log_lik= 1000,
           data= list(dat))

class(foo1)

# this gives me the print that I want; but throws two errors
# other things that I've tried have just done evaluated print.default()
print(foo1)

Summary method

## Summary
setGeneric("summary")

summary.foo <- function(obj) {
  print(obj)

  lapply(obj@data, dim)
}

setMethod("summary", signature= "foo",
  summary.foo)

summary(foo1) # works for this toy example. Doesn't work with my real code
# output for my real example
> Length           Class            Mode 
      1        mod_imputeMulti         S4 

I assume this is a simple fix to my ignorance, but I'm not sure what. Thanks in advance!

Upvotes: 1

Views: 622

Answers (1)

Martin Morgan
Martin Morgan

Reputation: 46866

S4 uses show() rather than print. The generic already exists

getGeneric("show")

so your job is to implement a method

setMethod("show", "foo", function(object) {
    cat("I'm a foo\n")
})

summary is an S3 generic and from ?Methods the advice is to implement an S3 method and an S4 method

summary.foo <- function(object, ...) {
    ## implement summary.foo
    "I'm a foo"
}

setMethod("summary", "foo", summary.foo)

The last line has as a side-effect the creation of an S4 generic on "summary" for reasons outlined on ?Methods; it may be useful to create the S4 generic explicitly,

setGeneric("summary")

summary.foo <- function(object, ...) {
    ## implement summary.foo
    "I'm a foo"
}

setMethod("summary", "foo", summary.foo)

before setting the method on it.

If you were to implement an entirely new generic and method, then code would follow the pattern

setGeneric("bar", function(x, ...) standardGeneric("bar"))

setMethod("bar", "foo", function(x, ...) {
    ## implement 'bar,foo-method'
})

In this case there would be no need to create an S3 generic or S3 method.

Upvotes: 1

Related Questions