[Rd] Overloading S4 methods

luke-tierney at uiowa.edu luke-tierney at uiowa.edu
Tue Jun 7 15:15:15 CEST 2011


On Mon, 6 Jun 2011, John Chambers wrote:

> This is a bug, medium-subtle, but also raises an interesting software design 
> point.
>
> The Bug:
>
> Nothing specific about "ANY" and "missing", but the issue is whether the 
> method was inherited (the "ANY" case) or defined directly (the "missing" 
> case).
>
> Generic functions keep a cached table of dispatched methods, to save 
> determining inherited methods repeatedly for calls with the same signature. 
> When pkg B is loaded, the inherited methods are reset, but apparently the 
> directly defined ones were not (but should have been if pkg B overrides the 
> method).
>
> It's interesting that this bug seems not to have been reported before, which 
> leads to:
>
> The Software Design Point:
>
> When a package (B) extends the class/method software in another package (A), 
> typically B adds new classes and perhaps new generic functions with methods 
> for previous classes in A as well as classes in B.  It might also extend the 
> behavior for classes in A to other generic functions.
>
> What is less usual is to directly override an existing method for a class 
> that belongs to A.  Notice that there can be side-effects, such as behavior 
> of examples or tests in package A depending on whether B has been loaded or 
> not.  And objects created entirely from A could have their computations 
> change after B was loaded.

Dylan is simliar in using a generic funciton model. One of the Dylan
books -- I forget which one -- strongly recomends that a library only
define a method if either it also defines the generic or if it defines
one of the classes the method is specialized on.  THis isn't an enforced
requirement but a strong recommendation.

Best,

luke

>
> Nothing at all illegal here, and we'll make it work.  But a more predictable 
> implementation for most applications would, say, define a new class in B that 
> extended the class in A.  In your example (very helpful, by the way) one 
> might have a class "mynumB", perhaps with the same slots as "mynum" but with 
> modified behavior.
>
> If you want to keep the current implementation, though, a workaround until 
> the bug is fixed would be something like:
>
> setMethod("plot", c("mynum", "missing"), getMethod("plot", c("mynum", 
> "missing")))
>
> executed after B is attached (I think it could be in the .onLoad function for 
> B, but have not tested that).
>
> John
>
>
> On 6/6/11 4:11 AM, Iago Mosqueira wrote:
>> On Wed, Jun 1, 2011 at 6:04 PM, Martin Morgan<mtmorgan at fhcrc.org>  wrote:
>>> On 06/01/2011 04:39 AM, Iago Mosqueira wrote:
>>>> 
>>>> Dear all,
>>>> 
>>>> I am experiencing some problems with S4 method overloading. I have
>>>> defined a generic for graphics:plot, using
>>>> 
>>>> setGeneric("plot", useAsDefault = plot)
>>>> 
>>>> and with
>>>> 
>>>> importFrom('graphics', 'plot') and
>>>> 
>>>> exportMethods('plot') in the NAMESPACE file of pkg A.
>>> 
>>> I'd guess you were creating two generics (explicitly in pkgA, implicitly 
>>> in
>>> pkgB). Maybe
>>>
>>>   export(plot)
>>> 
>>> in NAMESPACE of pkg A,
>>>
>>>   importFrom('pkgA', plot)
>>>   exportMethods(plot)
>>> 
>>> in pkg B. Feel free to post to the list if that's helpful.
>>> 
>>> Martin
>>> 
>>>> 
>>>> I then proceed to define a method for signature c('myS4class',
>>>> 'missing'). This works as expected: selectMethod('plot',
>>>> c('myS4class', 'missing')) returns the newly defined method, and the
>>>> method gets called when invoked.
>>>> 
>>>> Another pkg, B, wishes to overload this and redefines the method for
>>>> the same signature. A method is defined for c('myS4class', 'missing'),
>>>> and exported on the NAMESPACE. The new method is shown by
>>>> selectMethod() after pkg B has been loaded, but a call to
>>>> 
>>>> plot(anobjectofmyS4class)
>>>> 
>>>> comes up with the result of running the first method, from pkg A. I
>>>> have tried importing 'plot' in B's NAMESPACE from both graphics or A,
>>>> but the end result is the same.
>>>> 
>>>> Package B does the same thing for a method created by pkg A, myMethod,
>>>> and that works fine.
>>>> 
>>>> Any pointers or where this might be going wrong? How is it that a
>>>> different method than the one shown by selectMethod() is being run?
>>>> Something to do with the 'missing' part of the signature?
>>>> 
>>>> Many thanks,
>>>> 
>>>> 
>>>> 
>>>> Iago Mosqueira
>> 
>> Dear all,
>> 
>> I have tried Martin's suggestion, but the problem persists. It seems
>> to be related to having 'missing' in the signature, as doing the same
>> kind of overloading for c('myclass', 'ANY') work as expected.
>> 
>> I am attaching 2 simple packages where I attempt this repeated
>> overloading of plot for the same class. Script below, also found in
>> Bpkg/tests.test.R, shows what I have encountered so far:
>> plot('myclass', 'ANY') can be re-overloaded, but plot('myclass',
>> 'missing') cannot in the same way. If I run
>> 
>> trace("plot", browser, exit=browser, signature = c("mynum", "missing"))
>> 
>> the  new method is actually called.
>> 
>> Any hint on what I am doing wrong or where to look for an explanation
>> will be much appreciated.
>> 
>> Best regards,
>> 
>> 
>> Iago Mosqueira
>> 
>> 
>> 
>> ______________________________________________
>> 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
>

-- 
Luke Tierney
Statistics and Actuarial Science
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:      luke at stat.uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



More information about the R-devel mailing list