On Tue, Apr 26, 2016 at 2:16 PM, Martin Morgan <martin.mor...@roswellpark.org> wrote: > > > On 04/26/2016 04:47 PM, Michael Lawrence wrote: >> >> On Tue, Apr 26, 2016 at 11:00 AM, Aaron Lun <a...@wehi.edu.au> wrote: >>> >>> Dear List, >>> >>> When a S4 method for the same class is defined in two separate packages >>> (i.e., under the same generic), and both packages are loaded into a R >>> session, it seems that the method from the package loaded later clobbers >>> the >>> method from the package loaded first. Is it possible to specifically call >>> the method in the first package when both packages are loaded? If not, >>> how >>> should we protect against this? >>> >>> To give some context; the csaw package currently defines a normalize() >>> method for SummarizedExperiment objects, using the generic from >>> BiocGenerics. However, if some other hypothetical package (I'll call it >>> "swings", for argument's sake) were to define a normalize() method with a >>> SE >>> signature, and if the swings package were to be loaded after csaw, then >>> it >>> seems that all calls to normalize() would use the method defined by >>> swings, >>> rather than that defined by csaw. >>> >>> Now, for usual functions, disambiguation would be easy with "::", but I >>> don't know whether this can be done in the S4 system, given that the >>> details >>> of dispatch are generally hidden away. The only solution I can see is for >>> csaw (and/or swings) to define a SE subclass; define the normalize() >>> method >>> using the subclass as the signature, such that S4 dispatch will now go to >>> the correct method; and hope that no other package redefines normalize() >>> for >>> the subclass. >>> >>> Is this what I should be doing routinely, i.e., define subclasses and >>> methods for those subclasses in all my packages? Or am I missing >>> something >>> obvious? I would have expected such clashes to be more of a problem, >>> given >>> how many new packages are being added to BioC at every release. >>> >> >> I would recommend against defining subclasses of basic data structures >> that differ only in their behavior. The purpose of >> SummarizedExperiment is to store data. One might use inheritance to >> modify how the data are stored, or to store new types of data, >> although the latter may be best addressed through composition. >> >> To extend behavior, define methods. The generic represents the verb >> and thus the semantics of the operation. In general, method conflicts >> indicate that the design is broken. In this case, the normalize() >> generic has a very general name. There is no one way to "normalize" a >> SummarizedExperiment. It would be difficult for the reader to >> understand such ambiguous code. To indicate a specific normalization >> algorithm, we either need a more specific generic or we need to >> parameterize it further. >> >> One way to make more specific generics would be to give them the same >> name, "normalize", but define them in different namespaces and require >> :: qualification. That would mean abandoning the BiocGenerics generic >> and it would only work if each package provides only one way to >> normalize. Or, one could give them different names, but it would be >> difficult to select a natural name, and it's not clear whether the >> abstract notion of normalization should be always coupled with the >> method. >> >> A more flexible/modular approach would be to augment the signature of >> BiocGenerics::normalize to indicate a normalization method and rely on >> dual-dispatch: >> >> normalize(se, WithSwings()) >> normalize(se, WithCSaw()) >> >> Roughly, one example of this approach is >> VariantAnnotation::locateVariants() and its variant type argument. > > > I like the dual dispatch method quite a bit (but wonder why we get several > swings but only one csaw? Maybe a csaw implies two participants [though I > think I once in a while csaw-ed alone], so a singular csaw and a pair of > swings balance out?), partly because it's very easy to extend (write another > method) and the second argument can be either lightweight or parameterized. >
I could go along with the dual dispatch. "Swings" is short for "Set of swings". Usually, there are several swings in a row, but only one see-saw. > From a user perspective normalizeCsaw / normalizeSwings makes the available > options only a tab key away; maybe that's why Michael suggested With*? > That's a good point. > Martin > >> >> The affy package (or something around it) auto-qualifies the generic >> via a method argument; something like S3 around S4. For example >> normalize(se, "swings") would call normalize.swings(se), where >> normalize.swings itself could be generic. Another way to effect >> cascading dispatch is through composition, where the method object >> either is a function or can provide one to implement the normalization >> (emulating message passing OOP), which would allow normalize() to >> implemented simply as: >> >> normalize <- function(x, method, ...) normalizer(method)(x, ...) >> >> One issue is that the syntax is a bit unconventional and users might >> end up preferring the affy approach, with a normalize_csaw() and >> normalize_swings(). But I like the modular, dynamic approach outlined >> above. >> >> Thoughts? >> >> Michael >> >>> Cheers, >>> >>> Aaron >>> >>> _______________________________________________ >>> Bioc-devel@r-project.org mailing list >>> https://stat.ethz.ch/mailman/listinfo/bioc-devel >>> >> >> _______________________________________________ >> Bioc-devel@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/bioc-devel >> > > > This email message may contain legally privileged and/or confidential > information. If you are not the intended recipient(s), or the employee or > agent responsible for the delivery of this message to the intended > recipient(s), you are hereby notified that any disclosure, copying, > distribution, or use of this email message is prohibited. If you have > received this message in error, please notify the sender immediately by > e-mail and delete this email message from your computer. Thank you. > _______________________________________________ Bioc-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/bioc-devel