I am using setMethod to override the 'summary' function for objects of different classes.
Originally, I used this approach:
setMethod('summary', "class_1",
function(object, ...) {
#code for class_1 summary here...
}
)
setMethod('summary', "class_2",
function(object, ...) {
#code for class_2 summary here...
}
)
setMethod('summary', "class_3",
function(object, ...) {
#code for class_3 summary here...
}
)
...and so on for each class.
However, there are 12 different classes altogether, so the code became very repetitive. Wishing to avoid such repetition, I created a function containing the class names:
all_classes = function() {
c("class_1", "class_2", "class_3") #and so on for each class
}
Then I used lapply:
lapply(
1:length(all_classes()),
function(k)
setMethod('summary', all_classes()[k],
function(object, ...) {
#code here...
}
)
)
This works, but I would like to know if there is a better way of achieving my aim of compactly creating a 'summary' function for each different class.
Thanks,
John.
The S4 system in R is a system for object oriented programing. Confusingly, R has support for at least 3 different systems for object oriented programming: S3, S4 and S5 (also known as reference classes).
S4 provides a formal approach to functional OOP. The underlying ideas are similar to S3 (the topic of Chapter 13), but implementation is much stricter and makes use of specialised functions for creating classes ( setClass() ), generics ( setGeneric() ), and methods ( setMethod() ).
The S3 and S4 software in R are two generations implementing functional object-oriented programming. S3 is the original, simpler for initial programming but less general, less formal and less open to validation. The S4 formal methods and classes provide these features but require more programming.
An S3 class is the most prevalent and used class in R programming. It is easy to implement this class and most of the predefined classes are of this type. An S3 object is basically a list with its class attributes assigned some names. And the member variable of the object created is the components of the list.
A facade pattern implements light-weight methods on top of an underling work-horse function. Usually each method does some preliminary processing before invoking the work-horse function. In the simple case where there is no preliminary processing and you have no interest in the return value of setClass, it makes sense to use a for loop rather than lapply. So
.my_summary <- function(object, ...) {}
for (cl in all_classes())
setMethod(summary, cl, .my_summary)
Also, that .my_summary
works on several classes implies that the classes share common structure, hence might be arranged into a class hierarchy and a method defined on the base class.
setClass("A", representation(x="numeric"))
setClass("A1", contains="A")
setClass("A2", contains="A")
setMethod(summary, "A", function(object, ...) {})
In S4 one can use multiple inheritance to provide a kind of aspect-oriented programming
setClass("Summary")
setMethod(summary, "Summary", function(object, ...) {})
setClass("B1", contains=c("A", "Summary"))
B1 then inherits data (slot x) from A, and behavior from Summary. Method dispatch in this case can get confusing (which method is selected if both A and Summary have a summary method?).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With