[Bioc-devel] Problem with generic methods name conflicts

Martin Morgan mtmorgan at fhcrc.org
Thu Oct 13 20:57:21 CEST 2011


On 10/13/2011 10:45 AM, Stephanie M. Gogarten wrote:
> If a package is listed in "Depends", should it also be listed in
> "Imports"? I initially thought that this was redundant, and assumed that
> any package in Depends should be imported (unless it does not have a
> namespace). However, I tried to import a package (sandwich) which did
> not follow that rule - it depended on zoo but did not import it, thus
> forcing me to depend on it in order to use its functions within my own
> package (see recent discussion on R-devel). It seems to me that the best

Hi Stephanie --

Yes, sandwich was relying on finding symbols on the search path, 
fortuitously successful because of its Depends: zoo and failing for you 
because your Imports: sandwich does not add zoo to the search path (and 
for itself if the user had loaded zoo, then another package that masked 
zoo's symbols, then sandwich).

So lesson 1: Use Imports: and importFrom for symbols your package 
references.

Also, sandwich was 'broken', and the best outcome is to fix it; the 
work-around is to use Depends, but that work-around shouldn't drive best 
practice.

> solution is to avoid listing packages twice in the DESCRIPTION file, and
> to import anything in "Depends" unless there is some very good reason
> not to. But if the convention is to explicitly list all imports in the
> "Imports" field, I will follow that.

The arguments for not import'ing everything are somewhat compelling -- 
more efficient symbol look-up (performance), fewer collisions within 
your name space (sloth), and more robust software (doesn't matter when 
the author of Foo adds a symbol 'a', masking the previously unambiguous 
Bar::a). So,

Lesson 2: importFrom, rather than import

In terms of

 > solution is to avoid listing packages twice in the DESCRIPTION file

The starting point is to only use Imports: and importFrom, thinking 
selfishly as a developer who wants to minimize exposure to the whims of 
other packages and the user search path and for your user not wanting to 
clutter their work space with unnecessary symbols / help functions, etc.

Lesson 3: Use Imports: rather than Depends:, unless necessary.

When is it good practice to use Depends:? An answer might be because 
functions in your package return to the user objects (e.g., 
ExpressionSet) that can only be manipulated if they have access to that 
package (Biobase); maybe there are similar situations.

Lesson 4: Use Depends: Foo if return objects from your function are from 
package Foo.

So finally both Depends: and Imports: ? I think Depends: is sufficient, 
but I'd prefer the explicit indication of intention -- not all Depends: 
will be import'ed. But this is a little open to discussion

Lesson 5: Depends'ing and Imports'ing the same package is not strictly 
required (Depends: is sufficient)

Martin

>
> Stephanie
>
> On 10/13/11 10:08 AM, bioc-devel-request at r-project.org wrote:
>> ------------------------------
>>
>> Message: 5
>> Date: Thu, 13 Oct 2011 09:52:45 -0700
>> From: Martin Morgan<mtmorgan at fhcrc.org>
>> To: Herb Holyst<holyst at mail.med.upenn.edu>
>> Cc:bioc-devel at r-project.org, Wade Rogers<rogersw at mail.med.upenn.edu>
>> Subject: Re: [Bioc-devel] Problem with generic methods name conflicts
>> Message-ID:<4E97175D.1060001 at fhcrc.org>
>> Content-Type: text/plain; charset=ISO-8859-1; format=flowed
>>
>> On 10/13/2011 08:04 AM, Herb Holyst wrote:
>>> > Hi,
>>> >
>>> > I am hoping someone can point me in the right direction. I received
>>> a courtesy message from the Marc Carlson the our package flowFP had
>>> compilation errors, and after a bit of poking I discovered the
>>> Biobase added a new generic method called 'counts' which we had
>>> previously defined in flowFP. Since our package depends on Biobase we
>>> have a name collision.
>>> >
>>> > Here is the definition of our 'counts' generic out of flowFP's
>>> AllGenerics.R file:
>>> > ##
>>> =========================================================================
>>>
>>> > ## counts Methods.
>>> > ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>>> - - - - -
>>> > if (!isGeneric("counts")) {
>>> > setGeneric("counts", function(object, ...) standardGeneric("counts"))
>>> > }
>> I think that this construct pre-dates name spaces; it's weird (to me) to
>> define a method on a generic that one doesn't know about, e.g., maybe
>> 'counts' is documented to return a vector of European nobleman. It also
>> implies that 'counts' is found on the user search path rather than in
>> the package name space, so sometimes the intended counts is found,
>> sometimes not.
>>
>> These days I think that one would importFrom(Biobase, counts) and then
>> setMethod on the known generic (if Biobase has an appropriate counts
>> generic) or create a new generic (which I think would not normally be
>> the case).
>>
>> A secondary question that quickly comes up is how to make the user aware
>> of the generic 'counts'.
>>
>> On the one hand (I think this is the usual solution) it might be
>> appropriate to (in the DESCRIPTION file)
>>
>> Depends: Biobase
>> Imports: Biobase
>>
>> and (in the NAMESPACE file)
>>
>> importFrom(Biobase, counts)
>> exportMethods(counts)
>>
>> which arranges for the counts generic from Biobase to be available to
>> you for attaching methods, and to the user via the standard search path,
>> and for the methods defined in your package to be associated with that
>> generic.
>>
>> On a second hand one might think that, while your package has a use for
>> some-of-Biobase, the user does not have a use for all-of-Biobase so
>>
>> Imports: Biobase
>>
>> and
>>
>> importFrom(Biobase, counts)
>> export(counts)
>>
>> which allows you to add your methods to Biobase::counts, then passes
>> Biobase::counts through to be visible to the user. This seems awkward;
>> it requires that you document the 'counts' generic (you're the one
>> making it available to the user) even though the generic is in Biobase.
>> The motivation for not attaching Biobase to the search path is probably
>> part of the motivation for a BiocGenerics class -- too much clutter for
>> the user.
>>
>> On the third hand one might forgo Biobase entirely (neither Depends: nor
>> Imports:), define a generic counts in your own package and export that.
>> Let the user disambiguate if they happen to load Biobase in addition to
>> your package. For disparate data types and questions this might be
>> appropriate, but for data types shared by different packages it
>> unfortunately leads to a multiplication of classes and a confusion of
>> interfaces.
>>
>> On the fourth hand, perhaps your package has a use for some of Biobase
>> but the user does not. So Imports: and importFrom, with no exports.
>>
>> There are likely to be other hands.
>>
>> Martin
>>
>>
>
> _______________________________________________
> Bioc-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/bioc-devel


-- 
Computational Biology
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109

Location: M1-B861
Telephone: 206 667-2793



More information about the Bioc-devel mailing list