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