[Rd] Problem with S4 inheritance: unexpected re-initialization?

Herve Pages hpages at fhcrc.org
Tue Apr 3 23:52:43 CEST 2007


Hi Christian,

I can only give you a few reasons why IMO it is very unlikely that anybody
will be able to help you on this, with the current form of your post.

1) Unless you have a really good reason to do so, don't attach a package
   to your post. Do your best to provide a few lines of code that anybody
   can easily copy and paste into their session.

2) Your package is messy (yes I looked at it). You have far too many classes
   with far too many slots that we don't care about. If you could provide
   the smallest possible set of classes with the smallest possible set of slots
   with the smallest possible set of generics and methods that still allow to
   reproduce the issue you want to show us, that would help!

3) You show us an example where BaseClass is VIRTUAL (which is indeed how it is
   defined in your package) and then an example where BaseClass is NOT VIRTUAL.
   How can we reproduce the latter? Don't expect people to go into your package,
   change the class definition, reinstall, restart R and then run your example!

4) Note that for clarity and conformance to almost universal convention, it's
   better to use arrows pointing from derived classes to base classes
   in your inheritance tree.

5) It's good to provide the inheritance tree, but it's better when it's complete.
   I've looked at what you actually have in your package and the complete
   inheritance tree is something like this:

     BaseClass <- SubClassA
               <- SubClassB <- SubSubClassA
                            <- SubSubClassB

   Where is the SubClassA class in the inheritance tree that you included in your
   post below?

6) Another thing I note is that you have a naming problem: any reason why you name
   "SubSubClassA" a subclass of SubClassB? Given that you also have defined SubClassA,
   this can only lead to confusion!

7) You need to use proper terminology if you expect people to follow you. In your post
   below, every time you instanciate a class you say that your are creating it:
     o "First, I need to create SubClassA..."
     o "I create both subclasses, SubSubClassA and SubSubClassB..."
     o etc...
   Creating a class is not the same as instanciating it!

8) You start your examples by "First, I need to create SubClassA..." so you are
   introducing us a class that doesn't show up in your inheritance tree so we don't
   know how it is related to the other classes. Also you say that you "need" to
   create SubClassA but we have no idea why!

9) You have a slot in SubClassB that is of class SubClassA! This means "a SubClassB
   object _is_ a BaseClass object and it _has_ a slot that is itself a BaseClass
   object (since a SubClassA object is a BaseClass object too)". I hope that this
   is really what you want... but maybe this could be related to the fact that you
   see 2 instanciations of BaseClass when you instanciate SubSubClassA or SubSubClassB.

10) You have several different issues (initialize called multiple times when you expect
    only 1 time, setValidity not called, etc..). May be they are related, maybe they
    are not. If you can isolate those problems and make a separate post for each of them,
    that would help too.

You'll be surprised, but once you've made the effort to follow those recommendations,
it's most likely that you will have a better understanding of what's going on. And you
might even be able to sort out these issues by yourself!

Cheers,
H.


cstrato wrote:
> Dear S4 experts,
> 
> Since I was reminded that I posted a similar question some time ago,
> I am attaching a modified version of my demo package, which allows me
> to track what happens during initialization of the following similar
> subclasses:
>   SubSubClassA <- SubClassB <- BaseClass
>   SubSubClassB <- SubClassB <- BaseClass
> 
> First, I need to create SubClassA:
>> library(myclasspkg)
>> subA <-
> new("SubClassA",filename="OutSubA",filedir="/Volumes/CoreData/CRAN/Workspaces/rclasspkg",mytitle="TitleSubA")
> 
> 
> Then, I create both subclasses, SubSubClassA and SubSubClassB, either
> with a virtual BaseClass or with a non-virtual BaseClass:
> 
> 1. new("SubSubClassA"): BaseClass is VIRTUAL
>> subsubA <-
> new("SubSubClassA",filename="MyFileName",filedir="/Volumes/CoreData/CRAN/Workspaces/rclasspkg",subA=subA)
> 
> [1] "------initialize:SubSubClassA------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------"
> [1] "------setValidity:SubClassB------"
> [1] "------setValidity:SubSubClassA------"
> 
> As far as I understand the S4 classes, this is the correct initialization
> workflow that I expect. The resulting object "subsubA" is correct.
> 
> However, when BaseClass is not virtual, I get the following unexpected
> initialization workflow:
> 
> 2. new("SubSubClassA"): BaseClass is NOT VIRTUAL
>> subsubA <-
> new("SubSubClassA",filename="MyFileName",filedir="/Volumes/CoreData/CRAN/Workspaces/rclasspkg",subA=subA)
> 
> [1] "------initialize:SubSubClassA------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------" (called but NOT executed!)
> [1] "------initialize:BaseClass------" (2.initialization, why?)
> [1] "------setValidity:BaseClass------"
> [1] "------setValidity:SubClassB------"
> [1] "------setValidity:SubSubClassA------"
> 
> The first call to setValidity is not executed, and BaseClass is
> initialized twice, the second time in a completely wrong way, which
> normally results in an error. Interestingly, the resulting object
> "subsubA" is still correct.
> 
> The results are completely different for SubSubClassB:
> 
> 3. new("SubSubClassB"): BaseClass is VIRTUAL
>> subsubB <-
> new("SubSubClassB",filename="MyFileNameB",filedir="/Volumes/CoreData/CRAN/Workspaces/rclasspkg",subA=subA)
> 
> [1] "------initialize:SubSubClassB------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> [1] "------initialize:SubClassA------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------"
> [1] "------setValidity:SubClassA------"
> [1] "------setValidity:BaseClass------"
> [1] "------setValidity:SubClassB------"
> Error in validObject(.Object) : invalid class "SubClassB" object:
> 'filename' is missing
> 
> For some unknown reason SubClassA is initialized and BaseClass is
> initialized three times. SetValidity is called until an error occurs.
> 
> Things get more weird when BaseClass is not virtal:
> 
> 4. new("SubSubClassB"): BaseClass is NOT VIRTUAL
>> subsubB <-
> new("SubSubClassB",filename="MyFileNameB",filedir="/Volumes/CoreData/CRAN/Workspaces/rclasspkg",subA=subA)
> 
> [1] "------initialize:SubSubClassB------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> [1] "------initialize:SubClassA------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------"
> [1] "------setValidity:SubClassA------"
> [1] "------setValidity:BaseClass------"
> [1] "------initialize:BaseClass------"
> [1] "------setValidity:BaseClass------"
> [1] "------setValidity:SubClassB------"
> Error in validObject(.Object) : invalid class "SubClassB" object:
> 'filename' is missing
> 
> It seems that initialization occurs in an endless cycle until an
> error occurs.
> 
> Finally, let us look what happens when I follow the usual convention
> where callNextMethod() is called first:
> 
> 5. new("SubSubClassA"): callNextMethod() as 1.command; BaseClass is VIRTUAL
>> subsubA <-
> new("SubSubClassA",filename="MyFileName",filedir="/Volumes/CoreData/CRAN/Workspaces/rclasspkg",subA=subA)
> 
> [1] "------initialize:SubSubClassA------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> 
> The object "subsubA" is created correctly, however, setValidity()
> is never called.
> 
> The same is true for SubSubClassB:
> 
> 6. new("SubSubClassB"): callNextMethod() as 1.command; BaseClass is VIRTUAL
>> subsubB <-
> new("SubSubClassB",filename="MyFileNameB",filedir="/Volumes/CoreData/CRAN/Workspaces/rclasspkg",subA=subA)
> 
> [1] "------initialize:SubSubClassB------"
> [1] "------initialize:SubClassB------"
> [1] "------initialize:BaseClass------"
> 
> The object "subsubB" is for the first time created correctly, however,
> once again setValidity() is never called.
> 
> Maybe, I am misunderstanding an important part of creating S4 classes.
> I would be really greatful, if the S4 experts could explain me what
> happens here and what might be wrong with my demo package.
> 
> As a side note, when studying the code of the S4 packages "Biobase",
> "affy" and "oligo", I made the observation, that none of these packages
> calls "initialize" and "setValidity" for all classes and sub-classes.
> 
> Thank you very much in advance.
> Best regards
> Christian
> 
> 
> ------------------------------------------------------------------------
> 
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list