Re: [Rd] setIs and method dispatch in S4 classes

From: John Chambers <jmc_at_r-project.org>
Date: Mon 10 Apr 2006 - 13:53:35 GMT

 From your description of the application, it sounds like you would be better off just forcing "+" to behave as you want. Using inheritance is a much more powerful mechanism & can introduce results you don't want, as it seems to have in this case.

An important point about using inheritance is that the subclass is a asserted to be substitutable for the superclass for ALL purposes. This applies whether using "contains=" or setIs().

When the focus is on a particular function, it's usually better to implement methods for that function, maybe along with setAs() methods--not setIs().

It seems likely that such a solution would be cleaner in design, not to mention that it would likely work. (see also suggestion below)

Peter Ruckdeschel wrote:

>Hi Seth ,
>
>thank you for your reply.
>
>Seth Falcon <sfalcon@fhcrc.org> writes:
>
>
>
>>Peter Ruckdeschel <Peter.Ruckdeschel@uni-bayreuth.de> writes:
>>
>>
>>
>>
>>>## now: B00 mother class to B01 and B02, and again B02 "contains" B01 by
>>>setIs:
>>>setClass("B00", representation(a="numeric"))
>>>setClass("B01", representation(a="numeric",b="numeric"), contains= "B00")
>>>setClass("B02", representation(a="numeric",d="numeric"), contains= "B00")
>>>setIs("B02","B01",coerce=function(obj){new("B01", a=obj@a, b=obj@d)},
>>> replace=function(obj,value){new("B01", a=value@a, b=value@b)})
>>>
>>># now two "+" methods for B00 and B01
>>>setMethod("+", signature=c("B00","B00"), function(e1,e2){e1@a+e2@a})
>>>setMethod("+", signature=c("B01","B01"), function(e1,e2){e1@b+e2@b})
>>>
>>>x1=new("B02", a=1, d=2)
>>>x2=new("B02", a=1, d=3)
>>>
>>>x1+x2 ## 2 --- why?
>>>
>>>
>>>
>>>
>>My impression from reading over the man page for setIs, is that it
>>isn't intended to be used to override the existing inheritance
>>hierarchy. It also mentions that the return value is the extension
>>info as a list, so that could also be useful in understanding what
>>setIs is doing. Here's the output for your example:
>>
>> Slots:
>>
>> Name: a d
>> Class: numeric numeric
>>
>> Extends:
>> Class "B00", directly
>> Class "B01", directly, with explicit coerce
>>
>>Use the contains arg of setClass to define the superclasses. With the
>>contains arg, the order determines the precedence for method lookup.
>>But I suspect you know that already.
>>
>>
>>
>>
>Yes, I have been aware of this, thank you.
>
>
>
>>>Is there a possibility to force usage of the B01 method /without/
>>>explicitely coercing x1,x2 to B01, i.e. interfere in the dispatching
>>>precedence, telling R somehow (by particular arguments for setIs ?)
>>>to always use the is-relation defined by setIs first before mounting
>>>the hierarchy tree?
>>>
>>>
>>>
>>>
>>Perhaps explaining a bit more about what you are trying to accomplish
>>will allow someone to provide a more helpful suggestion than mine :-)
>>
>>
>
>In the "real" context, B00 stands for a class "AbscontDistribution",
>which implements absolutely continuous (a.c.) distributions. B01 is
>class "Gammad" which implements Gamma distributions, and B02 is
>class "Exp" which implements exponential distributions. The method
>still is "+", but interpreted as convolution.
>
>For a.c. distributions, the default method is an FFT-based numerical
>convolution algorithm, while for Gamma distributions (with the same
> scale parameter), analytic, hence much more accurate convolution
>formulas are used. For "Exp", I would tell R that it also 'is' a "Gammad"
>distribution by a call to setIs and use the "Gammad"-method.
>
>Of course, I could also declare explicitly "+" methods for signatures
>c("Exp", "Exp"), c("Exp", "Gammad"), and c("Gammad", "Exp") in
>which I would then use as(.) to coerce "Exp" to "Gammad"
>(and again the same procedure for further Gamma-methods).
>
>But, this would create an extra (3 or possibly much more) methods
>to dispatch, and I doubt whether this really is the preferred
>solution.
>
>
Why not? And you can avoid some of the extra methods by defining a virtual class that is the union of the classes for which you want the new methods.

Something like (untested code!)

setClassUnion("analyticConvolution", c("Exp", "Gammad")) setMethod("+", c("analyticConvolution", "analyticConvolution"), ....)

>
>
>>If you know the inheritance structure you want before run-time, then
>>I'm not seeing why you wouldn't just use the contains arg
>>
>>
>
>I do not want to use the "+" method for "B00" for accuracy reasons
>(see above).
>
>The reason why I do not want to implement "B01" ("Gammad")
>as mother class of "B02" is that
>
>(a) the slot structure is not identical --- in the real context Gamma
>and Exp use different parametrizations ---
> + rate for "Exp" (cf ?rexp) and
> + shape for "Gammad" (cf rgamma)
>
>(b) also class "Weibull" could be used as mother class to "Exp",
>and I do not want to decide whether the Weibull or the
>Gamma is the (more) "legitimate" mother to Exp ;-)
>
>I know: 'contains' could be a vector of classes ---
>c("Gammad", "Weibull") --- but then which would be
>the correct slot structure for "Exp" the one of "Gammad"
>or the one of "Weibull" ?
>My context is a bad example, "Gammad", "Weibull"
>do have the same slots, but more generally this /is/ an issue...
>
>--- So my guess was to rather implement two 'is'-relations
>( "Exp" 'is' "Gammad" and "Exp" 'is' "Weibull")
>declared by 'setIs' , and then on run time let the
>dispatching mechanism decide whether to use
>a Gamma or a Weibull method.
>
>But maybe there is a better solution ?
>Any suggestions are welcome.
>
>
>
>>And if you want to force certain behavior at run-time, then I don't
>>see what's wrong with an explicit coercion using as(foo, "bar").
>>
>>
>
>If you have two objects E1, E2 of class "Exp" (with the same rate)
>you (or the user for whom we provide these classes) rather want to
>call "+" by E1 + E2 than
>by as(E1, "Gammad") + as(E2,"Gammad")
>...
>
>Anyway, thank you for your help
>
>Peter
>
>______________________________________________
>R-devel@r-project.org mailing list
>https://stat.ethz.ch/mailman/listinfo/r-devel
>
>
>

        [[alternative HTML version deleted]]



R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Tue Apr 11 02:37:23 2006

This archive was generated by hypermail 2.1.8 : Mon 10 Apr 2006 - 20:17:15 GMT