[Rd] Problem with S4 inheritance: unexpected re-initialization?
cstrato
cstrato at aon.at
Wed Apr 4 17:02:53 CEST 2007
Dear Herve
Thank you for your helpful comments, and I especially appreciate that
you tried to run my package. I will try to answer each point separately.
Herve Pages wrote:
> 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.
>
Sorrowly, sometimes, a few lines of code are not sufficient to show
the problem. Furthermore, most of the time there are complaints that
people do not provide enough information, an issue I wanted to avoid.
At the end of my answer I provide now the minimal necessary code for
people to easily copy-paste into their session.
Nevertheless, I also attach the same code as package, since some
problems only appear when compiling the package, concretely:
The behavior of the attached package is completely different, when
I "exportMethods("initialize")" in the NAMESPACE file or not. To see
the changes, please comment-out this one line in the NAMESPACE file.
> 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!
>
You are correct, I wanted to provide a complete demo-package. As
mentioned above, I provide now the minimal necessary code (at least
I hope so).
> 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!
>
I thought, it would be easy for developers to understand what I mean
and to simply comment-out the one line in the definition of BaseClass.
> 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.
>
Sorry, my mistake.
> 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?
>
Sorry, my mistake.
> 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!
>
Again, you are correct, my mistake. Here is the corrected inheritance tree:
BaseClass <- SubClassA
<- SubClassB <- SubSubClassB1
<- SubClassB <- SubSubClassB2
> 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!
>
You are correct, this was confusing. I meant, theat I create an object,
which is probably the same as instanciating a class?
Here is the actual code to use:
> subA <-
new("SubClassA",filename="OutSubA",filedir="/Volumes/CoreData/CRAN/",namesubA="NameSubA")
> subsubB1 <-
new("SubSubClassB1",filename="MyFileNameB1",filedir="/Volumes/CoreData/",subA=subA)
> subsubB2 <-
new("SubSubClassB2",filename="MyFileNameB2",filedir="/Volumes/CoreExtra",subA=subA)
> 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!
>
Once again you are correct, this was confusing. I need to create object
"subA" of class SubClassA, since it is a slot of SubClassB, and needs to
be included in the instanciation of objects "subsubB1" and "subsubB2".
> 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.
>
This is the most IMPORTANT point and may be the cause of my problems:
YES, both SubClassA and SubClassB are derived from BaseClass, AND
SubClassA is a slot of SubClassB. This is what I want indeed!
In real OOP languages such as C++ and Java this is no problem, and I
really hope that this is possible when using S4 classes, too.
> 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.
>
Once again, you are correct, and normally I post these poblems seperately.
However, since I discovered all these problems while trying to solve the
main problem with my classes myself, I have mentioned them in my post.
> 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!
>
As you see, I tried to follow most (all?) of your recommendations, but
sorrowly, the problem remains the same.
When you copy-paste the code below and then do:
subA <-
new("SubClassA",filename="OutSubA",filedir="/Volumes/CoreData/CRAN/",namesubA="NameSubA")
subsubB1 <-
new("SubSubClassB1",filename="MyFileNameB1",filedir="/Volumes/CoreData/",subA=subA)
subsubB2 <-
new("SubSubClassB2",filename="MyFileNameB2",filedir="/Volumes/CoreExtra",subA=subA)
you will see that "subA" and "subsubB1" give the correct result, but
"subsubB2" results in the error that "filename" is missing, although it
is supplied.
> Cheers,
> H.
>
>
>
Thus, I would really appreciate any help.
Best regards
Christian
# - - - - - - - - - - - - - - - - - - BEGIN - - - - - - - - - - - - - -
- - - - - - -
setClass("BaseClass",
representation(filename = "character",
filedir = "character",
"VIRTUAL"
# filedir = "character"
),
prototype(filename = character(),
filedir = as.character(getwd())
)
)#BaseClass
setClass("SubClassA",
representation(namesubA = "character"),
contains=c("BaseClass"),
prototype(namesubA = "")
)#SubClassA
setClass("SubClassB",
representation(subA = "SubClassA",
data = "data.frame"
),
contains=c("BaseClass"),
prototype(subA = new("SubClassA"),
data = data.frame(matrix(nr=0,nc=0))
)
)#SubClassB
setClass("SubSubClassB1",
contains=c("SubClassB")
)#SubSubClassB1
setClass("SubSubClassB2",
representation(namesubsubB2 = "character"),
contains=c("SubClassB"),
prototype(namesubsubB2 = "MySubSubB2")
)#SubSubClassB2
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
validMsg <- function(msg, result) {
if (is.character(result)) {
append(msg, result);
} else {
msg;
}#if
}#validMsg
pathFile <- function(filename=character(0), filedir=character(0)) {
print("------pathFile------")
if (length(filename) != 0) {
filename <- basename(filename);
}#if
if (length(filename) == 0) {
filename <- as.character("ERROR_MISSING_FILENAME");
}#if
if (dirname(filename) != ".") {
filedir <- dirname(filename);
}#if
if (filedir == "" || filedir == ".") {
filedir <- as.character(getwd());
}#if
if (substr(filedir, nchar(filedir), nchar(filedir)) == "/") {
filedir <- substr(filedir, 0, nchar(filedir)-1);
}#if
dirfile <- paste(filedir, "/", filename, sep="");
return(dirfile);
}#pathFile
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
"initialize.BaseClass" <-
function(.Object, filename=character(), filedir=as.character(getwd()),
...) {
print("------initialize:BaseClass------")
print(paste("BaseClass:init:class(.Object) = ", class(.Object)))
# .Object <- callNextMethod(.Object, ...);
dirfile <- pathFile(filename, filedir);
print(paste("BaseClass:init:dirfile = ", dirfile))
.Object <- callNextMethod(.Object, filename=filename,
filedir=filedir, ...);
.Object at filename <- filename;
.Object at filedir <- filedir;
.Object;
}#initialize.BaseClass
setMethod("initialize", "BaseClass", initialize.BaseClass);
setValidity("BaseClass",
function(object) {
print("------setValidity:BaseClass------")
print(paste("BaseClass:val:class(object) = ", class(object)))
msg <- NULL;
if (!(is.character(object at filedir))) {
# if (is.na(file.dir(object at filedir))) {
msg <- validMsg(msg,
paste(sQuote("filedir"), "is not a system
directory"));
}#if
print(paste("BaseClass:val:filedir = ",object at filedir))
if (is.null(msg)) TRUE else msg;
}
)#setValidity
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
"initialize.SubClassA" <-
function(.Object, namesubA="MyNameSubA", ...) {
print("------initialize:SubClassA------")
print(paste("SubClassA:init:class(.Object) = ", class(.Object)))
# .Object <- callNextMethod(.Object, ...);
if (namesubA == "") {
namesubA <- "DefaultNameSubA";
}#if
print(paste("SubClassA:init:namesubA = ", namesubA))
.Object <- callNextMethod(.Object, namesubA=namesubA, ...);
.Object at namesubA <- namesubA;
#validObject(.Object);
.Object;
}#initialize.SubClassA
setMethod("initialize", "SubClassA", initialize.SubClassA);
setValidity("SubClassA",
function(object) {
print("------setValidity:SubClassA------")
print(paste("SubClassA:val:class(object) = ", class(object)))
msg <- NULL;
strg <- object at namesubA;
if (!(is.character(strg) && nchar(strg) > 0)) {
msg <- validMsg(msg, paste(sQuote("namesubA"), "is missing"));
}#if
print(paste("SubClassA:val:namesubA = ",object at namesubA))
if (is.null(msg)) TRUE else msg;
}
)#setValidity
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
"initialize.SubClassB" <-
function(.Object, subA=new("SubClassA"), data = data.frame(), ...) {
print("------initialize:SubClassB------")
print(paste("SubClassB:init:class(.Object) = ", class(.Object)))
# .Object <- callNextMethod(.Object, ...);
.Object <- callNextMethod(.Object, subA=subA, data=data, ...);
.Object at subA = subA;
.Object at data = data;
.Object;
}#initialize.SubClassB
setMethod("initialize", "SubClassB", initialize.SubClassB);
setValidity("SubClassB",
function(object) {
print("------setValidity:SubClassB------")
print(paste("SubClassB:val:class(object) = ", class(object)))
msg <- NULL;
## check filename
strg <- object at filename;
# if (!(is(strg, "character") && nchar(strg) > 0)) {
if (!(is.character(strg) && length(strg) > 0)) {
msg <- validMsg(msg, paste(sQuote("filename"), "is missing"));
}#if
print(paste("SubClassB:val:filename = ",object at filename))
if (is.null(msg)) TRUE else msg;
}
)#setValidity
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
"initialize.SubSubClassB1" <-
function(.Object, ...) {
print("------initialize:SubSubClassB1------")
print(paste("SubSubClassB1:init:class(.Object) = ", class(.Object)))
.Object <- callNextMethod(.Object, ...);
#validObject(.Object);
.Object;
}#initialize.SubSubClassB1
setMethod("initialize", "SubSubClassB1", initialize.SubSubClassB1);
setValidity("SubSubClassB1",
function(object) {
print("------setValidity:SubSubClassB1------")
print(paste("SubSubClassB1:val:class(.Object) = ", class(object)))
msg <- NULL;
if (is.null(msg)) TRUE else msg;
}
)#setValidity
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
"initialize.SubSubClassB2" <-
function(.Object, namesubsubB2="MyNamesubsubB2", ...) {
print("------initialize:SubSubClassB2------")
print(paste("SubSubClassB2:init:class(.Object) = ", class(.Object)))
# .Object <- callNextMethod(.Object, ...);
## set default subsubnameB
if (namesubsubB2 == "") {
namesubsubB2 <- "DefaultNamesubsubB";
}#if
print(paste("SubSubClassB2:init:namesubsubB2 = ", namesubsubB2))
.Object <- callNextMethod(.Object, namesubsubB2=namesubsubB2, ...);
.Object at namesubsubB2 <- namesubsubB2;
#validObject(.Object);
.Object;
}#initialize.SubSubClassB2
setMethod("initialize", "SubSubClassB2", initialize.SubSubClassB2);
setValidity("SubSubClassB2",
function(object) {
print("------setValidity:SubSubClassB2------")
print(paste("SubSubClassB2:val:class(object) = ", class(object)))
msg <- NULL;
## check subsubnameB
strg <- object at namesubsubB2;
if (!(is.character(strg) && nchar(strg) > 0)) {
msg <- validMsg(msg, paste(sQuote("namesubsubB2"), "is missing"));
}#if
print(paste("SubSubClassB2:val:namesubsubB2 = ",object at namesubsubB2))
if (is.null(msg)) TRUE else msg;
}
)#setValidity
# - - - - - - - - - - - - - - - - END - - - - - - - - - - - - - - - - -
- - - - - -
-------------- next part --------------
A non-text attachment was scrubbed...
Name: myclasspkg2_0.1.1.tar.gz
Type: application/x-gzip
Size: 3445 bytes
Desc: not available
Url : https://stat.ethz.ch/pipermail/r-devel/attachments/20070404/0546a913/attachment.gz
More information about the R-devel
mailing list