From ?UseMethod
(also in the NEWS file):
UseMethod
creates a new function call with arguments matched as they came in to the generic. [Previously local variables defined before the call toUseMethod
were retained; as of R 4.4.0 this is no longer the case.]
With this dummy generic and its methods:
f <- function(x) {
y <- head(x, 1)
z <- tail(x, 1)
UseMethod("f")
}
f.numeric <- function(x) {
x + y + z
}
f.character <- function(x) {
paste(x, y, z)
}
In R >= 4.4.0, we have:
f(1:3)
# Error in f.numeric(1:3) : object 'y' not found
f(c("a", "b", "c"))
# Error in f.character(c("a", "b", "c")) : object 'y' not found
While in R < 4.4.0, we had:
f(1:3)
# [1] 5 6 7
f(c("a", "b", "c"))
# [1] "a a c" "b a c" "c a c"
What is now the recommended way to pass local variables to methods?
My use case involves several objects that are precomputed from x
before the call to UseMethod()
. I am wondering if there is an alternative to wrapping this step in a function that would be called in each method, e.g.:
f <- function(x) {
UseMethod("f")
}
g <- function(x) {
y <- head(x, 1)
z <- tail(x, 1)
list(y = y, z = z)
}
f.numeric <- function(x) {
yz <- g(x)
x + yz$y + yz$z
}
f.character <- function(x) {
yz <- g(x)
paste(x, yz$y, yz$z)
}
This remain less practical than the former behavior because objects are now nested in a list. Anyway, I wish to avoid code duplication in the methods because the common step is relatively long (in LOC not time).
How about this?
f <- function(x) {
y <- head(x, 1)
z <- tail(x, 1)
f_int(x, y, z)
}
f_int <- function(x, ...) UseMethod("f_int")
f_int.numeric <- function(x, y, z, ...) {
x + y + z
}
f_int.character <- function(x, y, z, ...) {
paste(x, y, z)
}
f(1:3)
#[1] 5 6 7
f(c("a", "b", "c"))
#[1] "a a c" "b a c" "c a c"