Dear Gabriel, thank you so much for the scrutiny you took to look into this. Your explanation gives me a much better sense for what may be going on.
Admittedly, I still find it hard to understand why setAs() may have a side effect on inheritance. Looking at the documentation of setAs() again, this is an expected behaviour of setIs(), but not from setAs(). Maybe it makes sense to add a respective explicit explanation in the documentation of setAs()? For the time being, my personal take away is that I will try to circumvent setClassUnion() in combination with setAs(). Thanks again Andreas Von: Gabriel Becker <gabembec...@gmail.com> Datum: Dienstag, 6. Oktober 2020 um 02:02 An: Blätte <andreas.blae...@uni-due.de> Cc: Peter Dalgaard via R-devel <r-devel@r-project.org> Betreff: Re: [Rd] S4 - inheritance changed by order of setClassUnion and setAs() 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<mailto: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<mailto: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