Peter Ruckdeschel
2006-Apr-12 11:27 UTC
[Rd] yet another problem with S4 dispatch (with setClassUnion)
Dear John and Seth, dear R-devels, once again the question of method dispatch in S4 -- this time with setClassUnion(); taking up your advice in https://stat.ethz.ch/pipermail/r-devel/2006-April/037200.html https://stat.ethz.ch/pipermail/r-devel/2006-April/037201.html I have been too quick in stating that>setClassUnion()---at least in my case---solves the problem; >The problem arises if I have a direct superclass "competing" with the new class generated by setClassUnion(); consider the following code: ## C00 mother class to C01 and C02 setClass("C00", representation(a="numeric"), prototype =c(a=0)) setClass("C01", representation(a="numeric",b="numeric"), contains= "C00") setClass("C02", representation(a="numeric",d="numeric"), contains= "C00") #with setClassUnion: setClassUnion("C01OrC02", c("C01","C02")) # "+" methods for C00 and C01OrC02 # that this is a function to be dispatched on two arguments is # not important for this example setMethod("+", signature=c("C00","C00"), function(e1,e2){e1 at a+e2@a}) setMethod("+", signature=c("C01OrC02","C01OrC02"), function(e1,e2){if(is(e1,"C01")) e10 <- e1 # else: explicit coercion from C02 to C01 else e10 <- new("C01", a=e1 at a, b=e1 at d) if(is(e2,"C01")) e20 <- e2 # else: explicit coercion from C02 to C01 else e20 <- new("C01", a=e2 at a, b=e2 at d) e10 at b+e20@b}) x1=new("C02", a=1, d=2) x2=new("C02", a=1, d=3) x1+x2 ## 2, i.e. uses C00-method # but I would like to force usage of C01OrC02-method Here the two classes C00 and C01OrC02 are direct superclasses to C02, which exactly reflects my application of distribution classes, confer https://stat.ethz.ch/pipermail/r-devel/2006-April/037190.html How does the dispatching mechanism decide between these two and is there a way to change precedence? Of course, I could implement a "+" method for C02 directly in this case, but suppose I have much more methods for C01 and I want to use /all/ of them for C02, and cannot organize things so that we have the inheritance chain C00 -> C01 -> C02. What is the preferred way of doing this? Thank you already for your attention, Peter
John Chambers
2006-Apr-12 13:20 UTC
[Rd] yet another problem with S4 dispatch (with setClassUnion)
As I think Seth told you before, if you want to control the order of
inheritance at the same level, you need to use the intended order in the
contains= argument to setClass. In your example (retaining the class
union, although it's not required, the superclass could just be an
ordinary virtual class),
setClassUnion("C01OrC02")
## C00 mother class to C01 and C02
setClass("C00", representation(a="numeric"), prototype
=c(a=0))
setClass("C01",
representation(a="numeric",b="numeric"),
contains= c("C01OrC02", "C00"))
setClass("C02",
representation(a="numeric",d="numeric"),
contains= c("C01OrC02", "C00"))
seems to give what you want.
> x1 + x2
[1] 5
> extends("C01")
[1] "C01" "C01OrC02" "C00"
To answer one of your other questions, the point about inheritance
asserting substitutability is that you now need to be sure that EVERY
method for C01OrC02 is preferred to a method for C00 for the new subclasses.
As a general design point, having these competing superclasses is likely
to confuse the user, if not the implementer. If you could, it would
make a clearer picture to have, e.g., C01orC02 be a subclass of C00.
Then the inheritance is obvious--C01or... is a parent, while C00 is a
grandparent. The special contains= then doesn't need to be repeated
for every subclass Cx.
Peter Ruckdeschel wrote:
>Dear John and Seth, dear R-devels,
>
>once again the question of method dispatch in S4 -- this time with
>setClassUnion(); taking up your advice in
>
>https://stat.ethz.ch/pipermail/r-devel/2006-April/037200.html
>https://stat.ethz.ch/pipermail/r-devel/2006-April/037201.html
>
>I have been too quick in stating that
>
>
>
>>setClassUnion()---at least in my case---solves the problem;
>>
>>
>>
>The problem arises if I have a direct superclass "competing"
>with the new class generated by setClassUnion();
>
>consider the following code:
>
>## C00 mother class to C01 and C02
>setClass("C00", representation(a="numeric"), prototype
=c(a=0))
>setClass("C01",
representation(a="numeric",b="numeric"), contains=
"C00")
>setClass("C02",
representation(a="numeric",d="numeric"), contains=
"C00")
>
>#with setClassUnion:
>setClassUnion("C01OrC02", c("C01","C02"))
>
># "+" methods for C00 and C01OrC02
># that this is a function to be dispatched on two arguments is
># not important for this example
>
>setMethod("+", signature=c("C00","C00"),
function(e1,e2){e1@a+e2@a})
>setMethod("+",
signature=c("C01OrC02","C01OrC02"),
> function(e1,e2){if(is(e1,"C01")) e10 <- e1
> # else: explicit coercion from C02 to C01
> else e10 <- new("C01", a=e1@a, b=e1@d)
> if(is(e2,"C01")) e20 <- e2
> # else: explicit coercion from C02 to C01
> else e20 <- new("C01", a=e2@a, b=e2@d)
> e10@b+e20@b})
>
>x1=new("C02", a=1, d=2)
>x2=new("C02", a=1, d=3)
>
>x1+x2 ## 2, i.e. uses C00-method
># but I would like to force usage of C01OrC02-method
>
>Here the two classes C00 and C01OrC02 are direct superclasses to
>C02, which exactly reflects my application of distribution classes,
>confer https://stat.ethz.ch/pipermail/r-devel/2006-April/037190.html
>
>How does the dispatching mechanism decide between
>these two and is there a way to change precedence?
>
>Of course, I could implement a "+" method for C02 directly
>in this case, but suppose I have much more methods for
>C01 and I want to use /all/ of them for C02, and cannot
>organize things so that we have the inheritance chain
>C00 -> C01 -> C02. What is the preferred way of doing
>this?
>
>Thank you already for your attention,
>Peter
>
>______________________________________________
>R-devel@r-project.org mailing list
>https://stat.ethz.ch/mailman/listinfo/r-devel
>
>
>
[[alternative HTML version deleted]]