Re: [Rd] setIs and method dispatch in S4 classes
Hi Seth , thank you for your reply. Seth Falcon [EMAIL PROTECTED] writes: Peter Ruckdeschel [EMAIL PROTECTED] 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, [EMAIL PROTECTED], [EMAIL PROTECTED])}, replace=function(obj,value){new(B01, [EMAIL PROTECTED], [EMAIL PROTECTED])}) # now two + methods for B00 and B01 setMethod(+, signature=c(B00,B00), function(e1,e2)[EMAIL PROTECTED]@a}) setMethod(+, signature=c(B01,B01), function(e1,e2)[EMAIL PROTECTED]@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... --- 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
Re: [Rd] setIs and method dispatch in S4 classes
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 [EMAIL PROTECTED] writes: Peter Ruckdeschel [EMAIL PROTECTED] 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, [EMAIL PROTECTED], [EMAIL PROTECTED])}, replace=function(obj,value){new(B01, [EMAIL PROTECTED], [EMAIL PROTECTED])}) # now two + methods for B00 and B01 setMethod(+, signature=c(B00,B00), function(e1,e2)[EMAIL PROTECTED]@a}) setMethod(+, signature=c(B01,B01), function(e1,e2)[EMAIL PROTECTED]@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
Re: [Rd] setIs and method dispatch in S4 classes
Hi John, I found your comments helpful, even though this isn't _my_ question. But now I have one of my own :-) John Chambers [EMAIL PROTECTED] writes: 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), ) Why class union here and not an abstract superclass? If you own the Exp and Gammad classes, would an abstract superclass work as well? I think so. However, if you don't own the Exp and Gammad classes, I can see that the class union approach allows you the flexibility of defining a superclass post-hoc. I guess I have the sense that class unions are fancy/tricky (a number of popular languages don't have that concept, AFAIK). That isn't a reason not to use them in a langauge that does support them, of course. It is an interesting design question. On the one hand, one could argue for abstract superclasses when possible because they are less tricky (and you need them when you want to share slots). On the other hand, the class union approach provides a more loosely coupled design since members of the union don't have to know about each other. Hmm, I think I understand class unions a lot better already. Thanks. If I'm terribly off-track, please let me know. + seth __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] setIs and method dispatch in S4 classes
Seth Falcon wrote: Hi John, I found your comments helpful, even though this isn't _my_ question. But now I have one of my own :-) John Chambers [EMAIL PROTECTED] writes: 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), ) Why class union here and not an abstract superclass? If you own the Exp and Gammad classes, would an abstract superclass work as well? I think so. Yes, as is said frequently of a certain other language There's more than one way to do it My own feeling is that class unions are a convenient shorthand clearer than explicitly defining the superclass and then having to establish the inheritance separately for the two subclasses. Although the documentation mentions that they _must_ be used for classes you don't own, that's not their only purpose. Virtual classes (ahem, I assume that's what you meant by abstract ;-)) may or may not have slots of their own. Creating a virtual class analyticConvolution and doing two setIs() calls would in fact be roughly equivalent to the setClassUnion, but not as clear, IMO. If the superclass was really crucial to the model, that would make it more natural to have it explicitly in the contains= for the individual subclasses. Here, though, it seems more like a computational convenience for a fairly small part of the overall package, so isolating it in a single setClassUnion() call seems more natural. Obviously, a question of taste and style. However, if you don't own the Exp and Gammad classes, I can see that the class union approach allows you the flexibility of defining a superclass post-hoc. I guess I have the sense that class unions are fancy/tricky (a number of popular languages don't have that concept, AFAIK). That isn't a reason not to use them in a langauge that does support them, of course. It is an interesting design question. On the one hand, one could argue for abstract superclasses when possible because they are less tricky (and you need them when you want to share slots). On the other hand, the class union approach provides a more loosely coupled design since members of the union don't have to know about each other. Hmm, I think I understand class unions a lot better already. Thanks. If I'm terribly off-track, please let me know. + seth __ 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
Re: [Rd] setIs and method dispatch in S4 classes
as a fan of S4 i had a look at this; more definitive replies are undoubtedly to come ## 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) the direct specification of containment in the next statement is important for the dispatch process setClass(B02, representation(a=numeric,d=numeric), contains= B00) if we omit the containment assertion your expectations are met setClass(B02, representation(a=numeric,d=numeric)) setIs(B02,B01,coerce=function(obj){new(B01, [EMAIL PROTECTED], [EMAIL PROTECTED])}, replace=function(obj,value){new(B01, [EMAIL PROTECTED], [EMAIL PROTECTED])}) two diagnostic steps that are illuminating are getClass(B02) under both approaches (with and without contains=B00 in definition of B02 class) and getMethods(+) under both approaches __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel