Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In R, how can I extend generic methods from one package in another?

I have a package PackageA with a generic function:

#' doWork
#' 
#' Do some work!
#'
#' @export
setGeneric(
    "doWork", 
    function(x) {

        standardGeneric("doWork")
    })

setMethod(
    "doWork", 
    signature = c("numeric"), 
    definition = function(x) {

        x == 10 # Some logic... 
    }

In PackageB, which depends on PackageA, I would like to add more methods to doWork:

#' @import PackageA
setMethod(
    "doWork", 
    signature = c("character"), 
    definition = function(x) {

        length(x) == 1 && x == "10" # Some more logic... 
    }

This works. However, it means that the user of PackageB must also library(PackageA).

This fails:

library(PackageB)

doWork("10") # Fails!

This works:

library(PackageA)
library(PackageB)

doWork("10")

I would like to use the generic from PackageA in PackageB, but not require PackageA to be loaded to use just the methods in PackageB.

How can I achieve this?

like image 545
sdgfsdh Avatar asked Jul 09 '15 12:07

sdgfsdh


People also ask

How do I create a generic function in R?

Generic functions are created and assigned by setGeneric or setGroupGeneric and, indirectly, by setMethod . As you might expect setGeneric and setGroupGeneric create objects of class "genericFunction" and "groupGenericFunction" respectively.

What is generic function in R?

A generic function is one which may be applied to different types of inputs producing results depending on the type of input. Examples are plot() and summary() We demonstrate these differences using sample data from. Dalgaard's Introductory Statistics with R.


1 Answers

This is actually documented, but it's not very clear; see section 1.5.6 of Writing R Extensions.

The trick is to import the generic from PackageA and then re-export it from PackageB. Using roxygen annotations, this looks like:

#' @importMethodsFrom PackageA doWork
#' @export 
setMethod(
    "doWork", 
    signature = c("character"), 
    definition = function(x) {

        length(x) == 1 && x == "10" # Some more logic... 
    })

When you call devtools::document(), this will fail unless you have first loaded PackageA (call library(PackageA)).

However, once built, PackageA is not required:

> library(PackageB)
> showMethods("doWork")
Function: doWork (package PackageA)
x="character"
x="numeric"

For reference, the auto-generated NAMESPACE file looks like:

exportMethods(doWork)
importMethodsFrom(PackageA, doWork)

This method produces no warnings about naming conflicts and so on, so it seems to be "kosher".

like image 103
sdgfsdh Avatar answered Oct 20 '22 15:10

sdgfsdh