7

I have written a package using S4 classes and would like to use the functions rbind, cbind with these defined classes.

Since it does not seem to be possible to define rbind and cbind directly as S4 methods I defined rbind2 and cbind2 instead:

setMethod("rbind2", signature(x="ClassA", y = "ANY"), 
    function(x, y) {
      # Do stuff ...
})

setMethod("cbind2", signature(x="ClassA", y = "ANY"), 
    function(x, y) {
      # Do stuff ...
})

From ?cbind2 I learned that these functions need to be activated using methods:::bind_activation to replace rbind and cbind from base.

I included the call in the package file R/zzz.R using the .onLoad function:

.onLoad <- function(...) {
  # Bind activation of cbind(2) and rbind(2) for S4 classes
  methods:::bind_activation(TRUE)
}

This works as expected. However, running R CMD check I am now getting the following note since I am using an unexported function in methods:

* checking dependencies in R code ... NOTE
Unexported object imported by a ':::' call: 'methods:::bind_activation'
  See the note in ?`:::` about the use of this operator.

How can I get rid of the NOTE and what is the proper way to define the methods cbind and rbind for S4 classes in a package?

user625626
  • 1,102
  • 2
  • 10
  • 16
  • Would you mind including the class definitions (e.g. `setClass("ClassA",...)`) of a couple of the S4 classes you are trying to add `rbind` and `cbind` methods for? It would make it easier work out a solution for your problem. – nrussell Jan 11 '15 at 14:37
  • 1
    The class definitions shouldn't really matter in this case since it is only a matter of method selection/dispatching. So you could use any definition like setClass("ClassA", representation( a = "numeric")). – user625626 Jan 11 '15 at 16:48
  • Also, could you possibly explain why "*...it does not seem to be possible to define rbind and cbind directly as S4 methods...*" - maybe add your code from attempting to implement this? – nrussell Jan 11 '15 at 17:53
  • As stated in the help page of cBind in the Matrix library: The base functions cbind and rbind are defined for an arbitrary number of arguments and hence have the first formal argument .... For that reason, S4 methods cannot easily be defined for binding together matrices inheriting from Matrix. – user625626 Jan 11 '15 at 22:05

1 Answers1

4

I think basically the cBind help page in the Matrix package was accurate historically, but not recently. Here's a class

.A = setClass("A", representation(x="numeric"))

There's no generic, so create one, dispatching on the '...' argument (see ?setMethod and ?dotsMethods)

getGeneric("cbind")
## NULL
setGeneric("cbind", signature="...")
## Creating a new generic function for 'cbind' in the global environment

Then implement a method

setMethod("cbind", "A", function(..., deparse.level=1) "cbind,A-method")
## [1] "cbind"

And finally use it

> cbind(.A(), .A())
[1] "cbind,A-method"

This is fine so long as the '...' arguments are the same (possibly derived) class, which is often good enough.

> cbind(.A(), integer())
     [,1]
[1,] ?  

I believe that bind_activation() has global effects, not just on dispatch in your package; it should be avoided (it is no longer used in the Matrix package, for instance).

Also, I think that this has been updated in R-devel


r67699 | lawrence | 2015-02-01 10:13:23 -0800 (Sun, 01 Feb 2015) | 4 lines

cbind/rbind now delegate recursively to cbind2 (rbind2) when at least one argument is an S4 object and S3 dispatch fails; also consider S4 inheritance during S3 dispatch in the *bind functions.

Martin Morgan
  • 45,935
  • 7
  • 84
  • 112