[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