Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad style to redefine non-S3 base functions as S3 functions in an R package?

Tags:

oop

r

So I'm working on an R package that use S3 classes, and it would be really nice if I could use sample as method for one of my classes. However, base already declares sample as a non-S3 function, so what I wonder is:

Is it bad style to redefine a non-S3 base function such as sample as an S3 function? And could this mess things up for users of my package?

A way you could redefine sample and still keep the base function working is:

sample.default <- base::sample
sample <- function(x, ...) {
  UseMethod("sample")
}
# This allows me to define a new sample method for my_special_class
sample.my_special_class <- function(...) {...}

But what I'm uncertain about is whether this will cause any trouble or namespace issues, for example, when loading other packages. I've also noticed that not many packages redefine sample, for example, dplyr uses sample_n and igraph uses sample_, and I thought that there might be some reason for this...

like image 884
Rasmus Bååth Avatar asked Feb 14 '17 20:02

Rasmus Bååth


1 Answers

Whether or not it's bad "style" is primarily opinion-based. But Writing R Extensions, Section 7.1 - Adding new generics tells you how to add new generics that mask base base/recommended functions. That said, your proposed solution is explicitly cautioned against in that section:

...a package can take over a function in the base package and make it generic by something like

 foo <- function(object, ...) UseMethod("foo")
 foo.default <- function(object, ...) base::foo(object)

Earlier versions of this manual suggested assigning foo.default <- base::foo. This is not a good idea, as it captures the base function at the time of installation and it might be changed as R is patched or updated.

One problem others may encounter is if another package also registers summary as a generic. Then packages depending on your package or the other package need to decide which generic to register their method with.

Not many packages redefine sample because it's usually not a good idea to mask base/recommended functions. That creates the potential for users to get different behavior at the top-level depending on whether or not your package is loaded.

One thing you certainly want to avoid is masking a generic in a base/recommended (or highly used) package. Doing so can prevent method dispatch at the top-level, causing headaches for users who expect the generic to work (e.g. dplyr::lag).

like image 154
Joshua Ulrich Avatar answered Oct 19 '22 22:10

Joshua Ulrich