Search code examples
ooprr-s3

Using sd as a generic function in R


If I a have a class called foo, then it is straightforward to overload the summary function

summary.foo = function(x, ...) print("bar")

However this technique does not work with the sd function, that is

> bar = createFooClass()
> sd.foo = function(x, ...) print("Hi")
> sd(bar)
  error: is.atomic(x) is not TRUE

What is the correct way of overloading this function?


Solution

  • You can hijack any non-generic function, make it (S3) generic and set the original version to be the default version. For example:

    ## make an S3 generic for sd
    sd <- function(x, ...) UseMethod("sd")
    ## take the usual definition of sd,
    ## and set it to be the default method
    sd.default <- stats::sd
    ## create a method for our class "foo"
    sd.foo = function(x, ...) print("Hi")
    

    A final step, if this is in a package, is to add a ... argument to sd.default to allow passing of package checks:

    formals(sd.default) <- c(formals(sd.default), alist(... = ))
    

    giving:

    > args(sd.default)
    function (x, na.rm = FALSE, ...) 
    NULL
    > args(stats::sd)
    function (x, na.rm = FALSE) 
    NULL
    

    This then gives the desired behaviour:

    > bar <- 1:10
    > sd(bar)
    [1] 3.027650
    > class(bar) <- "foo"
    > sd(bar)
    [1] "Hi"
    

    This is documented in section 7.1 of the Writing R Extensions manual