On Thu, Feb 19, 2009 at 8:56 AM, Wolfgang Huber <huber@ebi.ac.uk> wrote:

> Hi Martin
>
> the re-use of the Biobase::annotation generic by GSEABase and affyPLM is
> great, because it makes it easier for users to discover and use these
> functionalities provided from the different packages (compared to them being
> separate regular functions).
>
> You are right that the name masking issue is technically independent of
> whether you are dealing with an S4 generic or a regular function. However,
> anecdotal evidence I've seen seems to indicate that package developers more
> readily tend to use generic (in the ordinary sense of the word) names for
> S4-generic functions, which increases the frequency of masking events. As
> you say, those can easily be addressed on the package development level by
> using namespace tools, but are quite a pain for the end-user whose is
> writing scripts.
>
> The two questions that I had in mind (sorry that they were not expressed
> that clearly) regarding what we should consider "best practice" in this
> community:
>
> - Should you export common names like, say, "annotation", "normalize",
> "coef" for your package's functions even though you're aware of them being
> exported, with different bindings, from other packages that users may
> concurrently attach?
>

This is a good question. For me, it's important that names are descriptive
and easy to remember. Secondary concerns are things like ease of typing.
Whether a name interesects with one from another package that a user might
attach to the workspace is pretty far down the list. In the rare cases where
this occurs, it's always possible to qualify the name by its namespace, ie
IRanges::annotation(). Just a bit more typing. In this particular case, as
we were making a more general form of AnnotatedDataFrame (an AnnotatedList),
it made sense to use the established and familiar name. That in my opinion
trumps any conflict with Biobase.


> - What is the threshold at which it makes sense to switch from defining a
> regular function to making it a generic + 1 method? (From your arguments
> below one might conclude that one should always do the second?)
>

For me, the main concern is extensibility. One could very roughly think of a
generic function as a single method interface, in OOP terms. Programming to
interfaces is usually a good idea. The main advantage a normal function has
over a generic is performance. Thus, for internal functions that are
specific to a single class (a "private" method in a OOP language), it
usually makes sense to avoid the use of generics.

Just my 2 cents..

Michael


>
>
> Best wishes
>     Wolfgang
>
>
>
> ----------------------------------------------------
> Wolfgang Huber, EMBL-EBI, http://www.ebi.ac.uk/huber
>
> Martin Morgan wrote:
>
>> Wolfgang Huber <huber@ebi.ac.uk> writes:
>>
>>  Hi
>>>
>>> of course there is no fundamental reason why the same name should not
>>> be used for different things in different packages, and in many
>>> instances this is the most reasonable solution. However, I think the
>>> user-friendliness of the set of Bioconductor packages would be
>>> improved if authors tried to keep such instances to a minimum.
>>>
>>> Since there is considerable overlap and collaboration between the
>>> authors of Biobase and IRange I am optimistic that a (perhaps less
>>> modular but) more integrated solution could be found.
>>>
>>> Currently, the generic function Biobase::annotation has exactly one
>>> method, for signature "eSet", and the generic function
>>> IRanges::annotation has exactly one method, for signature
>>> "AnnotatedList". I.e. although they are generic functions in the
>>> S4-technical sense, neither is generic in the common sense of the
>>> word. I think it could be a goal for us that the concepts "S4" and
>>>
>>
>> Hi Wolfgang --
>>
>> Not exactly sure what you're getting at here (which doesn't bode well
>> for common sense on my part, I guess); I read this as saying these
>> functions might be 'regular', and not generic at all. But as you know
>>
>> * Methods are not restricted to definition in the package of the
>> generic. So there are two methods on Biobase::annotation after
>> library(GSEABase), three after library(affyPLM), etc.
>>
>> * Generics provide type checking that is useful even when there is a
>> single method (e.g., Biobase::annotation does not operate on, say, a
>> data.frame).
>>
>> * Generics help to define an API (e.g., Biobase::annotation's single
>> method operates on 4 different classes defined in Biobase). The API
>> can be discovered programmatically, modulo the quirks of showMethod
>> (the 'where' argument can be useful under the current regime).
>>
>> * Two identically named regular functions would conflict in the same
>> way, except perhaps without notifying the user.
>>
>> Also worth reiterating that the example I mentioned pointed to a bug
>> (relying on user search path for function discovery) that has been
>> resolved through use of a name space and 'imports'.
>> End users still have to contend with the competing functions (using
>> Biobase::annotation to disambiguate). This is unfortunate and perhaps
>> amenable to common sense, but independent of S4 / generics.
>>
>> Martin
>>
>>  "common sense" be not opposed to each other.
>>>
>>> Best wishes
>>>      Wolfgang
>>>
>>> ----------------------------------------------------
>>> Wolfgang Huber, EMBL-EBI, http://www.ebi.ac.uk/huber
>>>
>>> Martin Morgan wrote:
>>>
>>>> Laurent Gatto <l.gatto@dnavision.be> writes:
>>>>
>>>>  Dear Bioc developeRs,
>>>>>
>>>>> I noted recently that Biobase's 'annotation' and 'annotation<-'
>>>>> objects are masked by IRanges. Now calling annotation(AffyBatch),
>>>>> of annotation(ExpressionSet) throws an 'unable to find an inherited
>>>>> method for function "annotation", for signature "AffyBatch"' error.
>>>>> Some of my functions fail because they rely on functions that call
>>>>> annotation(AffyBatch).
>>>>> My questions are (1) is this the expected behaviour and if yes (2)
>>>>> how am I and/or upstream maintainers supposed to elegantly deal
>>>>> with it?
>>>>>
>>>> Hi Laurent -- I just came across this issue myself -- package A
>>>> failed
>>>> because it called a function in package B which had a dependency on
>>>> package C which, due to changes in package D, now attached IRanges to
>>>> the search path. Package B then found IRange::annotation on the search
>>>> path, instead of Biobase::annotation.
>>>> The solution was easy, in the end -- add
>>>>  importMethodsFrom(Biobase, annotation)
>>>> to the NAMESPACE of package B, and move Biobase from 'Depends:' to
>>>> 'Imports:' in package B, which is definitely the Right Thing To Do. It
>>>> doesn't matter now that IRanges is on the user search path, package B
>>>> always gets the function it wants.
>>>> The solution is less elegant for a function that is not in a name
>>>> space, e.g., because the user is writing it in the global environment,
>>>> as in your example below. Then the solution is to use
>>>>  Biobase::annotation(eset)
>>>> in place of annotation(eset).
>>>> There might be additional technical solutions that Biobase / IRanges
>>>> /
>>>> Biostrings package authors can explore for this particular case...
>>>> Martin
>>>>
>>>>  Illustrative code and sessionInfo are given below.
>>>>>
>>>>> I hope that I am not missing anything obvious here.
>>>>>
>>>>> Thank you in advance.
>>>>>
>>>>> Laurent
>>>>>
>>>>>
>>>>> -- R code ---------------------------------------
>>>>>
>>>>>> source("http://bioconductor.org/biocLite.R")
>>>>>> update.packages(rep=biocinstallRepos(), ask=FALSE)
>>>>>> library(affydata)
>>>>>>
>>>>> Loading required package: affy
>>>>> Loading required package: Biobase
>>>>>
>>>>> Welcome to Bioconductor
>>>>>
>>>>>  Vignettes contain introductory material. To view, type
>>>>>  'openVignette()'. To cite Bioconductor, see
>>>>>  'citation("Biobase")' and for packages 'citation(pkgname)'.
>>>>>
>>>>>  data(Dilution)
>>>>>> annotation(Dilution)
>>>>>>
>>>>> [1] "hgu95av2"
>>>>>
>>>>>> library(IRanges)
>>>>>>
>>>>> Attaching package: 'IRanges'
>>>>>
>>>>>
>>>>>        The following object(s) are masked from package:Biobase :
>>>>>
>>>>>         annotation,
>>>>>         annotation<-
>>>>>
>>>>>        The following object(s) are masked from package:base :
>>>>>
>>>>>         cbind,
>>>>>         order,
>>>>>         pmax,
>>>>>         pmax.int,
>>>>>         pmin,
>>>>>         pmin.int,
>>>>>         rbind,
>>>>>         rep.int,
>>>>>         table
>>>>>
>>>>>> annotation(Dilution)
>>>>>>
>>>>> Error in function (classes, fdef, mtable)  :   unable to find an
>>>>> inherited method for function "annotation", for signature
>>>>> "AffyBatch"
>>>>>
>>>>>> Biobase:::annotation(Dilution)
>>>>>>
>>>>> [1] "hgu95av2"
>>>>>
>>>>>> sessionInfo()
>>>>>>
>>>>> R version 2.9.0 Under development (unstable) (2009-02-12 r47911)
>>>>> i686-pc-linux-gnu
>>>>> locale:
>>>>>
>>>>> LC_CTYPE=en_US.UTF-8;LC_NUMERIC=C;LC_TIME=en_US.UTF-8;LC_COLLATE=en_US.UTF-8;LC_MONETARY=C;LC_MESSAGES=en_US.UTF-8;LC_PAPER=en_US.UTF-8;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=en_US.UTF-8;LC_IDENTIFICATION=C
>>>>>
>>>>> attached base packages:
>>>>> [1] stats     graphics  grDevices utils     datasets  methods
>>>>> base
>>>>> other attached packages:
>>>>> [1] IRanges_1.1.38  affydata_1.11.3 affy_1.21.7     Biobase_2.3.10
>>>>> loaded via a namespace (and not attached):
>>>>> [1] affyio_1.11.3        preprocessCore_1.5.3 tools_2.9.0
>>>>>
>>>>> _______________________________________________
>>>>> Bioc-devel@stat.math.ethz.ch mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/bioc-devel
>>>>>
>>>>
>>
> _______________________________________________
> Bioc-devel@stat.math.ethz.ch mailing list
> https://stat.ethz.ch/mailman/listinfo/bioc-devel
>

	[[alternative HTML version deleted]]

