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

From: Peter Ruckdeschel <>
Date: Mon 10 Apr 2006 - 09:07:27 GMT

Hi Seth ,

thank you for your reply.

Seth Falcon <> writes:

>Peter Ruckdeschel <> 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.

> 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...  

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 mailing list Received on Mon Apr 10 22:05:52 2006

This archive was generated by hypermail 2.1.8 : Mon 10 Apr 2006 - 18:16:55 GMT