I am trying to understand what the purpose of the generic
argument of NextMethod()
is.
# example data
x <- as.Date(c("2022-01-01", "2023-01-01", "1900-01-01", "2024-01-01"))
# gives cumulative maximum as expected
cummax.Date <- function(x, ...) .Date(NextMethod(), cl = oldClass(x))
cummax(x)
#> [1] "2022-01-01" "2023-01-01" "2023-01-01" "2024-01-01"
# gives cumulative minimum as expected
cummin.Date <- function(x, ...) .Date(NextMethod(), cl = oldClass(x))
cummin(x)
#> [1] "2022-01-01" "2022-01-01" "1900-01-01" "1900-01-01"
Quite often, the generic is called explicitely.
cummin.Date <- function(x, ...) .Date(NextMethod(generic = "cummin"), cl = oldClass(x))
cummin(x)
#> [1] "2022-01-01" "2022-01-01" "1900-01-01" "1900-01-01"
However, explicitly calling the generic does not impact the result whatsoever, no matter if it exists or not.
# still returns the cumulative minimum
cummin.Date <- function(x, ...) .Date(NextMethod(generic = "cummax"), cl = oldClass(x))
cummin(x)
#> [1] "2022-01-01" "2022-01-01" "1900-01-01" "1900-01-01"
# still returns the cumulative minimum
cummin.Date <- function(x, ...) .Date(NextMethod(generic = "foobar"), cl = oldClass(x))
cummin(x)
#> [1] "2022-01-01" "2022-01-01" "1900-01-01" "1900-01-01"
NextMethod
uses argument generic
only if it does not find the symbol .Generic
in the calling environment of the method. That happens only in atypical usage:
> .S3method("mean", "a", function(x, ...) { rm(.Generic); NextMethod() })
> mean(structure(1:6, class = "a"))
Error in NextMethod() : generic function not specified
> .S3method("mean", "b", function(x, ...) { rm(.Generic); NextMethod("diff") })
> mean(structure(1:6, class = "b"))
[1] 1 1 1 1 1
attr(,"class")
[1] "b"
> .S3method("mean", "c", function(x, ...) { .Generic <- "diff"; NextMethod() })
> mean(structure(1:6, class = "c"))
[1] 1 1 1 1 1
attr(,"class")
[1] "c"
It is undocumented (I think), but visible in the sources of the internal do_nextmethod
, which uses readS3VarsFromFrame
(defined elsewhere) to locate .Generic
.
I don't think that anyone would recommend assigning to .Generic
, removing .Generic
, or otherwise calling NextMethod
in a context where .Generic
is not there. Indeed, I think that the advice in help("NextMethod")
about .Class
applies here:
Note that
.Class
is set when the generic is called, and is unchanged if the class of the dispatching argument is changed in a method. It is possible to change the method thatNextMethod
would dispatch by manipulating.Class
, but 'this is not recommended unless you understand the inheritance mechanism thoroughly' (Chambers & Hastie, 1992, p. 469).