Question

I am writing an S4 class and am working on the accessor methods. I would like to write a method that if you give it one or more of my S4 objects will return a vector with the contents of a certain slot. Here is some sample code

setClass(Class="TestClass",slots=c(Type="character"))   ### Creates Class             

setGeneric(name="getType",function(object){standardGeneric("getType")} )

setMethod(f="getType", signature="TestClass",      ### accessor for "TYPE
      function(object){object@Type})

Now I make two objects:

 FOO<-new("TestClass",Type="A")
 BAR<-new("TestClass",Type="B")

Using getType(FOO) works as planned. However when I do this:

Both<-c(FOO,BAR)
getType (Both)

rather than getting "A","B" I of course get:

Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘getType’ 
  for signature ‘"list"’

Which is not surprising. I know that I could write a function like

getType2<-function(object){sapply(object, FUN=getType)}

and that would give me what I want. However, is there some way to do this within the accessor function itself? Can I vectorize the @?

Was it helpful?

Solution

I think the answer is no, you cannot get dispatch on contents of a list; you could write a getType,list-method. Or you could create a TestList class that contains a list of Test classes and write a method for that. The IRanges package has a general container for this...

library(IRanges)
.TestList = setClass("TestList", contains="SimpleList", 
    prototype=c(elementType="Test"))
TestList = function(...) .TestList(listData=list(...))
lst = TestList(FOO, BAR)
lst[[1]]

Or in my opinion the best solution is to write your class so that it is vectorized already, in the same way that character() is vectorized -- 0, 1, or any number of 'Test' elements.

A simple example would be modelling a collection of people. The non-R way would think of one person per row, with a collection (here a list) representing several people:

.Person = setClass("Person", representation(First="character", Last="character"))
friends = list(.Person(First="Bill", Last="Smith"),
               .Person(First="Sue", Last="Bird"))

versus a more R way where the class models an entire table, with fields representing columns.

.People = setClass("People", representation(First="character", Last="character"))
setMethod(show, "People", function(object) {
    print(data.frame(First=object@First, Last=object@Last))
})

friends = .People(First=c("Bill", "Sue"), Last=c("Smith", "Bird"))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top