Search code examples
rr-s3

Get Methods Inherited from S3 Class and its Parent


If I have an S3 class that inherits from a parent, how can I return a list of generic methods that I can call - both from the S3 class and the parent.

So the class of the created objects is: c("my_s3_class", "parent_s3_class")

The following works fine for returning the methods on my_s3_class:

methods(class = my_s3_class)

But it doesn't include generic functions that are callable, but only implemented in the parent, parent_s3_class.

Ultimately I want to call every method using something like the below (this works, but doesn't include parent generic methods). The use of get() means that I can't use NextMethod() which otherwise would have been a reasonable workaround. Note I have an instance of my_s3_class which I've represented as my_s3_class_instance - this is just an implementation detail tho.

result <- sapply(methods(class = class(my_s3_class_instance)[1]),
                 function(f) {
                     print(paste("Executing:",f))
                     get(f)(my_s3_class_instance)})

Any ideas? Thanks!


Solution

  • You can iterate over the classes of an instance of your subclass. For example, suppose we have defined the following classes and methods:

    foo <- function(x, ...) {
        UseMethod("foo")
    }
    
    bar <- function(x) {
        class(x) <- c("bar", class(x))
        return(x)
    }
    
    baz <- function(x) {
        class(x) <- c("baz", "bar", class(x))
        return(x)
    }
    
    foo.bar <- function(x, ...) {
        cat("Bar:", x, "\n")
    }
    
    foo.default <- function(x, ...) {
        cat("Default:", x, "\n")
    }
    

    And we have created an instance of baz, the subclass of bar:

    my_instance <- baz(1)
    

    Now we could find all the callable methods, from baz and the parent(s):

    unname(unlist(sapply(class(my_instance), function(x) methods(class = x))))
    
     [1] "foo.bar"                        "all.equal.numeric"             
     [3] "as.data.frame.numeric"          "as.Date.numeric"               
     [5] "as.POSIXct.numeric"             "as.POSIXlt.numeric"            
     [7] "as.raster.numeric"              "coerce,ANY,numeric-method"     
     [9] "Ops,nonStructure,vector-method" "Ops,structure,vector-method"   
    [11] "Ops,vector,nonStructure-method" "Ops,vector,structure-method"  
    

    Now, calling them all is tougher, since they all have different arguments. Consider the following:

    sapply(unlist(sapply(class(my_instance), function(x) methods(class = x))),
           function(f) get(f)(my_instance, 2))
    
    Bar: 1 
    Error in as.Date.numeric(origin, ...) : 'origin' must be supplied
    

    Of course, we also probably need to eliminate things like "Ops,nonStructure,vector-method":

    z <- unname(unlist(sapply(class(my_instance), function(x) methods(class = x))))
    z[!grepl(",", z)]
    
    [1] "foo.bar"               "all.equal.numeric"     "as.data.frame.numeric"
    [4] "as.Date.numeric"       "as.POSIXct.numeric"    "as.POSIXlt.numeric"   
    [7] "as.raster.numeric"