Search code examples
rgenericsargumentsr-s3

How to set the additional arguments of a new generic to be the same as their default values in the default method


When implementing a generic method for a new class:

scale.newclass <- function(x, center = TRUE, scale = TRUE) {
    ...
}

How to guarantee that the default values for additional arguments center and scale always stay consistent with their default values in scale.default?

In other words - if in the future scale.default changes it's default argument to scale = FALSE, how to make sure scale.newclass defaults are also adjusted to match?


Solution

  • The method scale.default inherits the default values of its arguments from the generic function scale:

    identical(formals(scale), formals(scale.default))
    ## [1] TRUE
    

    Those values will not change unless the generic function changes, and if the generic function changes, then you'll be warned about inconsistencies by R CMD check. So the example doesn't quite motivate the problem ...

    Setting that aside, you can do this programmatically with formals<-:

    formals(scale.a) <- formals(scale.default)
    

    Well, that only works for generic functions not admitting a formal argument ...:

    any(names(formals(scale)) == "...")
    ## [1] FALSE
    

    In general, the formals of the two methods may not have the same length or the same names, and in that case you would want to be more careful:

    f <- function(x, ...) UseMethod("f")
    f.default <- function(x, a = 1, b = 2, c = a + b, ...) x
    f.a       <- function(x, a = 1, b = 1, c = a - b, ...) x
    
    form.default <- formals(f.default)
    form.a       <- formals(f.a)
    
    nms <- intersect(names(form.default), names(form.a))
    formals(f.a)[nms] <- form.default[nms]
    
    identical(formals(f.a), form.default)
    ## [1] TRUE
    

    Still, my feeling is that these kinds of "precautions" can cause more problems than they solve in the long run ...