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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With