From jmc at r-project.org  Tue Jun  7 23:10:16 2011
From: jmc at r-project.org (John Chambers)
Date: Tue, 07 Jun 2011 14:10:16 -0700
Subject: [Rd] Overloading S4 methods
In-Reply-To: <BANLkTi=EZozootp3Jc7EirNFxqm=wFpFSg@mail.gmail.com>
References: <BANLkTi=KwUzxy+3YA+HWmP-PPozD-g7zkg@mail.gmail.com>	<4DE6631A.9010104@fhcrc.org>	<BANLkTimCFhkqPq=3XowmiZVKDtwXhM4V3g@mail.gmail.com>	<4DED467F.1080006@r-project.org>	<alpine.DEB.2.00.1106070812100.1796@luke-inspiron>	<4DEE5A7B.8030903@r-project.org>
	<BANLkTi=EZozootp3Jc7EirNFxqm=wFpFSg@mail.gmail.com>
Message-ID: <4DEE93B8.2030507@r-project.org>

On 6/7/11 2:02 PM, Iago Mosqueira wrote:
> Can then the warning be turned off in any way to avoid it showing up
> on check? Maybe an argument to confirm 'I know what I am doing so I
> need no warning, thank you very much'.

Well, this is still new territory since the bug didn't seem to have been 
encountered before your example.  We won't add the warning in the 
immediate future, and as Luke pointed out, even Dylan just advises. 
This may be more a matter for a "code tools" approach.  So not to worry 
just yet!

John

>
>
> Iago
>
> On Tue, Jun 7, 2011 at 7:06 PM, John Chambers<jmc at r-project.org>  wrote:
>> Yes, Dylan is in many ways more authoritarian than R!  Possibly also with
>> fewer users to be annoyed.
>>
>> We might go to a warning as Iago suggests.  If we did add a warning, it
>> would be likely be more useful in the setMethod() call than at CMD check
>> time, after the package has been designed and implemented.
>>
>> John
>>
>> On 6/7/11 6:15 AM, luke-tierney at uiowa.edu wrote:
>>>
>>> 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
>>>>
>>>
>>
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



[Rd] Overloading S4 methods
John Chambers