I want to subclass an S4 class and add a special method to that subclass.
The method should work only for the subclass, it does not make sense for any other class in my application.
setClass("MySpecies", contains="Species", ##Species is an S4 class
representation(x="numeric"))
setMethod("initialize", "MySpecies", function(.Object, x, ...){
.Object@x <- x
args <- list(...)
for(i in seq_len(length(args))){
attr(.Object, names(args)[i]) <- args[[i]]
}
.Object
})
##CalcMatrix <- function(.Object, y){
## x <- .Object@x
## matrix(x, x*2, y*3)
##}
setGeneric("CalcMatrix", function(object, y){standardGeneric("CalcMatrix")})
setMethod("CalcMatrix", "MySpecies",function(object, y){
x <- object@x
matrix(x, x*2, y*3)
})
With the setGeneric it works, but do I really have to define a generic function although it will be used only with this object? The commented out part works, but then there is no check if the function is called with the right arguments. What is the correct way to do this?
Thanks in advance.
You’re wanting to use method dispatch, and every method needs to be associated with a generic, so yes,
setGenericis required.And for a little unasked-for advice… It’s a bit weird to use a formal class system (presumably because the well-defined classes help in writing more complicated programs) and then to subvert the structure by adding arbitrary attributes; these should really be additional, well-defined slots in your class.
Let’s make your example reproducible by defining
SpeciesAn implicit requirement for S4 classes is that
new("MySpecies")works; yourinitializemethod fails this test (becausexdoes not have a default value). In addition, it’s common practice to expect that initializingMySpeciescalls theinitializemethods for the classes it contains. One could writeNote
callNextMethod, so that the base class gets initialized properly. Using...and passing it tocallNextMethodmeans that slots that might be defined inSpecieswould also be initialized correctly. Also,xneeds to be after..., becauseinitializeis defined to take unnamed arguments that represent contained classes —new("MySpecies", new("Species"))is required to work, even if it is a way of constructing arguments that you do not use directly. Theinitializemethod above doesn’t actually do anything more than the default initialize method, so in reality (and this is often the case) it makes sense not to write an initialize method at all.And then in more recent R,
setClassreturns a default constructor soand then