Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override the implementation of a non-generic function in R

Tags:

r

r-s3

In R, I have an S3 class that emulates a 1D vector, and so I want to implement custom versions of mean, sum, max, etc. Let's say it looks like this:

my_class = function(){
  structure(list(), class='my_class')
}

All the above methods work fine, if I define mean.my_class etc:

mean.my_class = function(x){
  2
}

mean(my_class())

However, I would also like to do this for functions like var, which isn't a generic method. If I create such a function, and then call var on an instance of my class:

var.my_class = function(his){
  # Do stuff here
}

var(my_class())

I get the error:

Error in var(my_class()) : is.atomic(x) is not TRUE

This is because there is no generic var function, and it's just calling stats::var on my structure. How then can I provide a custom implementation if there isn't a generic method? I don't want to break the var method for regular vectors either.

like image 486
Migwell Avatar asked Oct 11 '25 16:10

Migwell


1 Answers

You can create your own generic with the same name and signature as the existing non-generic function:

var = function (x, y = NULL, na.rm = FALSE, use) UseMethod('var')
var.my_class = function (x, y, na.rm, use) 42

registerS3method('var', 'default', stats::var)
registerS3method('var', 'my_class', var.my_class)

… instead of manually copying the formal argument list for the generic function, you can instead use the following to generate it automatically:

var = function () UseMethod('var')
formals(var) = formals(stats::var)

— Of course the above only works if the caller calls your var function. If somebody invokes for instance stats::var, your generic won’t be found, and so no S3 method dispatch happens.


Beware that R 3.5 changed the way S3 method lookup works across environments, and merely defining an appropriately-named function is no longer sufficient for the method to be found from a different environment — you need to invoke registerS3method (not just for new generics like var but also for your mean!). Unfortunately there’s virtually no official documentation for this function, just some blog posts by Kurt Hornik.

like image 161
Konrad Rudolph Avatar answered Oct 14 '25 04:10

Konrad Rudolph