[Rd] S4 - inheritance changed by order of setClassUnion and setAs()
Gabriel Becker
g@bembecker @end|ng |rom gm@||@com
Tue Oct 6 02:02:07 CEST 2020
Andreas,
As far as I can tell (/conjecture), this is because the list of classes a
particular class inherits from directly is appended to as needed, and so
the order that a class extends others isd refined by the order that those
connections are defined.
We can see this with two setClassUnion calls, rather than required setAs:
> setClass("grandma", slots = c(a = "character"))
> setClass("mother", slots = c(b = "matrix"), contains = "grandma")
> setClass("daughter", slots = c(c = "list"), contains = "mother")
> setClassUnion(name = "mr_x", members = c("daughter", "mother"))
> setClassUnion(name = "mr_y", members = c("daughter", "mother"))
> getClass("daughter")
Class "daughter" [in ".GlobalEnv"]
Slots:
Name: c b a
Class: list matrix character
Extends:
Class "mother", directly
Class "mr_x", directly
Class "mr_y", directly
Class "grandma", by class "mother", distance 2
> setClass("grandma2", slots = c(a = "character"))
> setClass("mother2", slots = c(b = "matrix"), contains = "grandma2")
> setClass("daughter2", slots = c(c = "list"), contains = "mother2")
> setClassUnion(name = "mr_y2", members = c("daughter2", "mother2"))
> setClassUnion(name = "mr_x2", members = c("daughter2", "mother2"))
> getClass("daughter2")
Class "daughter2" [in ".GlobalEnv"]
Slots:
Name: c b a
Class: list matrix character
Extends:
Class "mother2", directly
Class "mr_y2", directly
Class "mr_x2", directly
Class "grandma2", by class "mother2", distance 2
Note that mr_y2 appears in the list before mr_x2 the second block. The same
thing is happening with setAs which (somewhat contrary to my expectations,
admittedly) causes extends to consider "daughter" to inherit *directly* from
"grandma" in your example (though it does note its via explicit coercion).
I think the take-away here is that when modifying the class inheritance
structure explicitly, via setClassUnion or setAs (or, I assume, setIs)
order inherently matters.
In fact order also matters for multiple inheritence via the normal contains
mechanism. In practice, how could it not matter?
Multiple inheritence is very powerful but dangerous.
> setClass("person1", slots = c(f = "character"))
> setClass("person2", slots = c(g = "character"))
> setClass("people1",* contains = c("person1", "person2")*)
> getClass("people1")
Class "people1" [in ".GlobalEnv"]
Slots:
Name: f g
Class: character character
Extends: "person1", "person2"
> setClass("people2", *contains = c("person2", "person1")*)
> getClass("people2")
Class "people2" [in ".GlobalEnv"]
Slots:
Name: g f
Class: character character
Extends: "person2", "person1"
> setGeneric("ohno", function(obj) standardGeneric("ohno")
+ )
[1] "ohno"
> setMethod("ohno", "person1", function(obj) "person1!")
> setMethod("ohno", "person2", function(obj) "person2! Oh No!")
*> ohno(new("people1"))*
*[1] "person1!"*
*> ohno(new("people2"))*
*[1] "person2! Oh No!"*
Not sure if that helps any or not, but thats what I see here. And again, if
I got anything wrong here, someone please correct me :)
Best,
~G
On Mon, Oct 5, 2020 at 1:47 PM Blätte, Andreas <andreas.blaette using uni-due.de>
wrote:
> Dear colleagues,
>
> there is a behaviour with S4 (virtual) classes that I find very hard to
> understand: Depending on the position
> of setAs(), the tree of inheritance changes.
>
> This is my baseline example that defines the classes "grandma", "mother",
> "daughter" and a virtual
> class "mr_x". For a new instance if "daughter", "mr_x" is betweeen
> "mother" and "grandma".
>
> setClass("grandma", slots = c(a = "character"))
> setClass("mother", slots = c(b = "matrix"), contains = "grandma")
> setClass("daughter", slots = c(c = "list"), contains = "mother")
> setClassUnion(name = "mr_x", members = c("daughter", "mother"))
> setAs(from = "daughter", to = "grandma", def = function(from)
> new("grandma"))
> is(new("daughter"))
>
> [1] "daughter" "mother" "mr_x" "grandma"
>
> Yet if I change the order of setAs() and setClassUnion(), this alters the
> pattern of inheritance.
>
> setClass("grandma", slots = c(a = "character"))
> setClass("mother", slots = c(b = "matrix"), contains = "grandma")
> setClass("daughter", slots = c(c = "list"), contains = "mother")
> setAs(from = "daughter", to = "grandma", def = function(from)
> new("grandma"))
> setClassUnion(name = "mr_x", members = c("daughter", "mother"))
> is(new("daughter"))
>
> [1] "daughter" "mother" "grandma" "mr_x"
>
> Is there a reasonable explanation for this behavior? I could not find any
> and I would appreciate
> your help. If it is not an unintended behavior, I find it very confusing
> and hard to anticipate.
>
> Kind regads
> Andreas
>
> --
> Prof. Dr. Andreas Blätte
> Professor of Public Policy and Regional Politics
> University of Duisburg-Essen
>
> [[alternative HTML version deleted]]
>
> ______________________________________________
> R-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
[[alternative HTML version deleted]]
More information about the R-devel
mailing list