[Rd] Proper way to define cbind, rbind for s4 classes in package

Michael Lawrence lawrence.michael at gene.com
Mon Feb 2 04:23:06 CET 2015


I've implemented the proposed changes in R-devel. Minimally tested, so
please try it. It should delegate to r/cbind2 when there is at least one S4
argument and S3 dispatch fails (so you'll probably want to add an S3 method
for your class to introduce a conflict, otherwise it will dispatch to
cbind.data.frame if one of the args is a data.frame). There may no longer
be a need for cBind() and rBind().

Michael

On Mon, Jan 26, 2015 at 3:55 AM, Martin Maechler <
maechler at lynne.stat.math.ethz.ch> wrote:

> >>>>> Michael Lawrence <lawrence.michael at gene.com>
> >>>>>     on Sat, 24 Jan 2015 06:39:37 -0800 writes:
>
>     > On Sat, Jan 24, 2015 at 12:58 AM, Mario Annau
>     > <mario.annau at gmail.com> wrote:
>     >> Hi all, this question has already been posted on
>     >> stackoverflow, however without success, see also
>     >>
> http://stackoverflow.com/questions/27886535/proper-way-to-use-cbind-rbind-with-s4-classes-in-package
> .
>     >>
>     >> 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 (see ?cBind) I defined
>     >> rbind2 and cbind2 instead:
>     >>
>
>     > This needs some clarification. It certainly is possible to
>     > define cbind and rbind methods. The BiocGenerics package
>     > defines generics for those and many methods are defined by
>     > e.g. S4Vectors, IRanges, etc.  The issue is that dispatch
>     > on "..." is singular, i.e., you can only specify one class
>     > that all args in "..." must share (potentially through
>     > inheritance).
>
>     > Thus, trying to combine objects from a
>     > different hierarchy (or non-S4 objects) will not
>     > work.
>
> Yes, indeed, that's the drawback
>
> I've been there almost surely before everyone else, with the
> Matrix package...
> and I have been the author of
>     cbind2(), rbind2(), and of course, of  cBind(), and rBind().
>
> At the time when I introduced these, the above possibility of
> writing S4 methods for  '...'  where not yet part of R.
>
>     > This has not been a huge problem for us in
>     > practice. For example, we have a DataFrame object that
>     > mimics data.frame. To cbind a data.frame with a DataFrame,
>     > the user can just call the DataFrame()
>     > constructor. rbind() between different data structures is
>     > much less common.
>
> well... yes and no.  Think of using the Matrix package, maybe
> with another package that defines another generalized matrix class...
> It would be nice if things worked automatically / perfectly there.
>
>     > The cBind and rBind functions in Matrix (and the r/cbind
>     > that get installed by bind_activation, the code is shared)
>     > work by recursing, dropping the first argument until two
>     > are left, and then combining with r/cbind2(). The Biobase
>     > package uses a similar strategy to mimic c() via its
>     > non-standard combine() generic. The nice thing about the
>     > combine() approach is the user entry point and the generic
>     > are the same, instead of having methods on rbind2() and
>     > the user calling rBind().
>
>     > I would argue that bind_activation(TRUE) should be
>     > discouraged,
>
> Yes, you are right Michael; it should be discouraged at least to
> be run in a *package*.
> One could think of its use by an explicit user call.
>
>     > because it replaces the native rbind and
>     > cbind with recursive variants that are going to cause
>     > problems, performance and otherwise. This is why it is
>     > hidden. Perhaps a reasonable compromise would be for the
>     > native cbind and rbind to check whether any arguments are
>     > S4 and if so, resort to recursion. Recursion does seem to
>     > be a clean way to implement "type promotion", i.e., to
>     > answer the question "which type should the result be when
>     > faced with mixed-type args?".
>
> Exactly.  That has been my idea at the time ..
> ((yes, I'm also the author of the  bind_activation()
>   "(mis)functionality".))
>
>     > Hopefully others have better ideas.
>
> that would be great.
>
> And even if not, it would be great if we could implement your
> idea
>     > Perhaps a reasonable compromise would be for the
>     > native cbind and rbind to check whether any arguments are
>     > S4 and if so, resort to recursion.
>
> without a noticable performance penalty in the case of no S4
> arguments.
>
> Martin
>
>
>     > Michael
>
>     >> 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?
>     >>
>     >> Best, mario
>     >>
>     >> ______________________________________________
>     >> R-devel at r-project.org mailing list
>     >> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>     > ______________________________________________
>     > R-devel at r-project.org mailing list
>     > https://stat.ethz.ch/mailman/listinfo/r-devel
>

	[[alternative HTML version deleted]]



More information about the R-devel mailing list