Skip to content

[Bioc-devel] Conflicting definitions for function redefined as S4 generics

7 messages · Michael Lawrence, Gabriel Becker, Ulrich Bodenhofer +1 more

#
[cross-posted to R-devel and bioc-devel]

Hi,

I am trying to implement a 'sort' method in one of the CRAN packages I 
am maintaining ('apcluster'). I started with using setMethod("sort", 
...) in my package, which worked fine. Since many users of my package 
are from the bioinformatics field, I want to ensure that my package 
works smoothly with Bioconductor. The problem is that the BiocGenerics 
package also redefines 'sort' as an S4 generic. If I load BiocGenerics 
before my package, everything is fine. If I load BiocGeneric after I 
have loaded my package, my setMethod("sort", ...) is overridden by 
BiocGenerics and does not work anymore. A simple solution would be to 
import BiocGenerics in my package, but I do not want this, since many of 
this package's users are outside the bioinformatics domain. Moreover, I 
am reluctant to include a dependency to a Bioconductor package in a CRAN 
package. I thought that maybe I could protect my setMethod("sort", ...) 
from being overridden by BiocGeneric by sealed=TRUE, but that did not 
work either. Any ideas are gratefully appreciated!

Thanks a lot,
Ulrich


------------------------------------------------------------------------
*Dr. Ulrich Bodenhofer*
Associate Professor
Institute of Bioinformatics

*Johannes Kepler University*
Altenberger Str. 69
4040 Linz, Austria

Tel. +43 732 2468 4526
Fax +43 732 2468 4539
bodenhofer at bioinf.jku.at <mailto:bodenhofer at bioinf.jku.at>
http://www.bioinf.jku.at/ <http://www.bioinf.jku.at>
#
Hi,

I agree. I can't think of an easy way to avoid this kind of clashes
between BioC and non-BioC S4 generics, other than by having things
like sort() already defined as an S4 generic in base R.

Note that, just having setMethod("sort", ...) in your package Ulrich, 
and not putting a setGeneric() statement, is usually the right thing
to do. Because then there will be no clash as long as everybody else
does the same thing. That's because if several packages with a
setMethod("sort", ...) statement are loaded, an implicit S4 generic
is created when the 1st package is loaded, and then "sort" methods
are attached to it when subsequent packages are loaded.

Unfortunately, the implicit S4 generic one gets when doing this
doesn't always have an optimum signature. For example, for sort()
we get dispatch on 'x' *and* 'decreasing':

   > sort
   standardGeneric for "sort" defined from package "base"

   function (x, decreasing = FALSE, ...)
   standardGeneric("sort")
   <environment: 0x230bf28>
   Methods may be defined for arguments: x, decreasing
   Use  showMethods("sort")  for currently available ones.

This is why in BiocGenerics we have:

   setGeneric("sort", signature="x")

The downside of this is that now if you load BiocGenerics after your
package, a new S4 generic is created for sort(), which overrides the
implicit S4 generic that was created when your package was loaded.
Of course we wouldn't need to do this in BiocGenerics if the implicit
S4 generic for sort() had the correct signature, or if this setGeneric()
statement we have in BiocGenerics was somewhere in base R.

Another reason for explicitly promoting some base R functions into
S4 generics in BiocGenerics is to have a man page for the generic.
That gives us a place to document some aspects of the S4 generic that
are not covered by the base man page. That's why BiocGenerics has
things like:

   setGeneric("nrow")

   setGeneric("relist")

The signatures of these generics is the same as the signature of
the implicit generic! But these explicit generics can be exported
and documented.

Back to the original issue: In the particular case of sort() though,
since base::sort() is an S3 generic, one possible workaround for you
is to define an S3 method for your objects.

Cheers,
H.
On 03/26/2014 06:44 AM, Michael Lawrence wrote:

  
    
#
I fully agree, Michael, that this would be a great thing to have! I have 
often wondered why R and the standard packages are still sticking so 
much to the old-style S3 flavor though S4 is part of standard R. I 
acknowledge that backward compatibility is important, but, as far as I 
got it, redefining a function or S3 generic as an S4 generic should not 
harm existing functionality (if done properly). If it turns out not to 
be a good option to do this in the base package, why not as part of the 
methods package? That will leave existing functionality of base 
unchanged and will provide a clean situation to all users/packages using S4.

This should not create a compatibility problem on the Bioconductor side 
either, since Bioconductor releases are explicitly bound to specific R 
versions. Once again: I fully support this idea (not only for sort(), 
but also for a wide range of other functions), though, not being an R 
core team member, I do not really feel in the position to demand such a 
fundamental change.

For the time being, it seems I have three options:

1) not supplying the sort() function yet (it is not yet in the release, 
but only in my internal devel version)
2) including a dependency to BiocGenerics
3) leaving the problem open, mentioning in the documentation that users 
who want to use apcluster in conjunction with Bioconductor should load 
BiocGenerics first

As far as I got it, there seems to be no other clean way to get rid of 
the problem, right?

Best regards,
Ulrich
On 03/26/2014 02:44 PM, Michael Lawrence wrote:
#
On 03/27/2014 02:13 AM, Ulrich Bodenhofer wrote:
4) define an S3 method, as mentioned in my previous post

H.