yet another problem with S4 dispatch (with setClassUnion)

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

yet another problem with S4 dispatch (with setClassUnion)

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

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: yet another problem with S4 dispatch (with setClassUnion)

John Chambers-2
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
>
>______________________________________________
>[hidden email] mailing list
>https://stat.ethz.ch/mailman/listinfo/r-devel
>
>  
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: yet another problem with S4 dispatch (with setClassUnion)

Peter Ruckdeschel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
 
Dear John,

sorry for having bothered you with these problems.

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

Apologies, but I did not catch this from Seth's mail; in fact Seth wrote

>> With the contains arg, the order determines the precedence for method
lookup.

sorry for coming up again with the same question.

> 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
Yes, it does. Thank you very much. Problem solved!

... and I have learned something ....

Besides the importance of order in the 'contains'-arg,
beforehand,  I had also somehow misunderstood the
purpose of setClassUnion():
I had thought setClassUnion()  was to circumvene the
modification of classes (not "owned" by me);
thus it was not obvious to me to write a class defined
by setClassUnion() into the 'contains'-argument.

BTW:

Is there a way to solve my problem without
modifying the 'contains'-arguments ---
e.g. if I do not "own" classes C01, C00, C02?
(This is not the case for my application, but
might be of general interest) .

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

Ok. This would be the case in my application.

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

Good point; I fixed this in our package.
Probably it is also a good idea then not to export this artificial
(but no longer VIRTUAL) intermediate class in the NAMESPACE file.

Thank you once again, you helped us a lot.
Peter


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (MingW32)
Comment: GnuPT 2.6.2.1 by EQUIPMENTE.DE
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
 
iD8DBQFEPbFex+/gN8KI3u0RAgE8AJ9/M6Q7F8ldGDLVjRCCXW6PdidJRwCfW2zd
rFlFbzuL4jbrav//lmrO2rE=
=iIbA
-----END PGP SIGNATURE-----


______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel