My S4 class has a method that is called many times. I noticed that the execution time is much slower than it would be if a similar function was called independently. So I ad
The cost is in method look-up, which starts from scratch in each iteration of your timing. This can be short-circuited by figuring out method dispatch once
METHOD <- selectMethod(method.foo, class(st))
for (i in seq(iters)) METHOD(st)
This (better method look-up) would be a very interesting and worth-while project; there are valuable lessons learned in other dynamic languages, e.g., inline caching mentioned on Wikipedia's dynamic dispatch page.
I wonder if the reason that you're making many method calls is because of incomplete vectorization of your data representation and methods?
This doesn't help you directly with your problem, but it's much easier to benchmark this sort of stuff with the microbenchmark package:
f <- function(x) NULL
s3 <- function(x) UseMethod("s3")
s3.integer <- function(x) NULL
A <- setClass("A", representation(a = "list"))
setGeneric("s4", function(x) standardGeneric("s4"))
setMethod(s4, "A", function(x) NULL)
B <- setRefClass("B")
B$methods(r5 = function(x) NULL)
a <- A()
b <- B$new()
library(microbenchmark)
options(digits = 3)
microbenchmark(
bare = NULL,
fun = f(),
s3 = s3(1L),
s4 = s4(a),
r5 = b$r5()
)
# Unit: nanoseconds
# expr min lq median uq max neval
# bare 13 20 22 29 36 100
# fun 171 236 270 310 805 100
# s3 2025 2478 2651 2869 8603 100
# s4 10017 11029 11528 11905 36149 100
# r5 9080 10003 10390 10804 61864 100
On my computer, the bare call takes about 20 ns. Wrapping it in a function adds about an extra 200 ns - this is the cost of creating the environment where the function execution happens. S3 method dispatch adds around 3 µs and S4/ref classes around 12 µs.