Dear Herve, dear Martin, First I want to thank Herve very much for your continuous efforts. You can not imagine, how relieved I was that you mangaged to reproduce this behavior.
Just when I wanted to send my reply to Herve, I received Martin's comments: As you mention, there were two problems in my example: 1. partial matching: Thank you for your explanation, now I hope that I understand the behavior. However, as Herve correctly mentioned, this is only a side issue. 2. lazy evaluation and validity methods: This is the real problem, that I try to solve since three weeks, and I am afraid, that I still do not know how to solve it. Following Herve's example, I have managed to reduce my own example so that it is only slightly larger than his example, however, now I had to expand it again to make my point, see the final code below. (For the moment I stick with my naming of the classes) The result I get is the following: > subsubB2 <- new("SubSubClassB2", filename="MyFileNameB2", nameB="MyNameB") ------initialize:SubSubClassB2------ ------initialize:SubClassB------ ------initialize:BaseClass------ BaseClass:init:filename = MyFileNameB2 ------setValidity:BaseClass------ ------initialize:SubClassB------ ------initialize:BaseClass------ BaseClass:init:filename = ERROR_FileName ------setValidity:BaseClass------ ------setValidity:SubClassB------ ------setValidity:SubClassB------ ------setValidity:SubSubClassB2------ SubSubClassB2:val:filename = MyFileNameB2 Although the final output gives the correct result "filename = MyFileNameB2", in the interim code, filename is set to "filename = ERROR_FileName". In my real package the line "filename <- ERROR_FileName" is replaced by a function. To take advantage of inheritance, I have defined "filename" in BaseClass, and I want to check for its validity only once in BaseClass. With the current information I have to re-evaluate my code in order to avoid "lazy evaluation", since this might be the problem. Thank you both for your extensive help. Best regards Christian # - - - - - - - - - - - - - - - BEGIN - - - - - - - - - - - - - - - - setClass("BaseClass", representation(filename = "character", "VIRTUAL"), prototype(filename = "DefaultFileName") ) setClass("SubClassB", representation(nameB = "character"), contains=c("BaseClass"), prototype(nameB = "NameB") ) setClass("SubSubClassB2", representation(nameB2 = "character"), contains=c("SubClassB"), prototype(nameB2 = "NameB2") ) setMethod("initialize", "BaseClass", function(.Object, filename="", ...) { cat("------initialize:BaseClass------\n") if (filename == "" || nchar(filename) == 0) filename <- "ERROR_FileName" cat("BaseClass:init:filename = ", filename, "\n", sep="") .Object <- callNextMethod(.Object, filename=filename, ...) [EMAIL PROTECTED] <- filename .Object } ) setValidity("BaseClass", function(object) { cat("------setValidity:BaseClass------\n") msg <- NULL str <- [EMAIL PROTECTED] if (!(is.character([EMAIL PROTECTED]))) msg <- cat("missing filename\n") if (is.null(msg)) TRUE else msg } ) setMethod("initialize", "SubClassB", function(.Object, nameB="", ...) { cat("------initialize:SubClassB------\n") .Object <- callNextMethod(.Object, nameB=nameB, ...) } ) setValidity("SubClassB", function(object) { cat("------setValidity:SubClassB------\n") TRUE } ) setMethod("initialize", "SubSubClassB2", function(.Object, ...) { cat("------initialize:SubSubClassB2------\n") .Object <- callNextMethod(.Object, ...) } ) setValidity("SubSubClassB2", function(object) { cat("------setValidity:SubSubClassB2------\n") cat("SubSubClassB2:val:filename = ", [EMAIL PROTECTED], "\n", sep="") TRUE } ) # - - - - - - - - - - - - - - - END - - - - - - - - - - - - - - - - - Martin Morgan wrote: > Christian, Herve -- > > In the end, I think you're being caught by partial matching in > function arguments: > > >> f <- function(x1) cat("x1:", x1, "\n") >> f(x="hello") >> > x1: hello > > In the functional call x gets matched to x1. In your initialization > method for SubSubClassB2, nameB gets matched to nameB2 and so not > passed as ... in the callNextMethod. > > The apparently extra calls to initialize with the wrong arguments come > about because of the validity methods -- validity gets checked by > coercing derived objects to their superclass, which involves a call to > 'new' (hence initialize) followed by copying appropriate slots. > > The funny effect where class(object) seems to trigger construction of > a new object is lazy evaluation -- the 'object' argument to > setValidity is not evaluated until needed, i.e., until class(object) > (anything would trigger this, including force(object)); only then do > you see the attempt to create the new object of the previous > paragraph. > > Without partial matching issues, the use of callNextMethod as here: > > setMethod("initialize", "SubSubClassB2", > function(.Object, nameB2="MyNameB2", ...) { > if (nameB2 == "") nameB2 <- "DefaultNameB2"; > callNextMethod(.Object, nameB2=nameB2, ...) > } > ) > > is fine (though weird to have a prototype, a named argument, and a > conditional assignment!). > > With > > setMethod("initialize", "SubSubClassB2", > function(.Object, ...) { > .Object <- callNextMethod() > if ([EMAIL PROTECTED] == "") [EMAIL PROTECTED] <- "DefaultNameB2" > .Object > } > ) > > as suggested by Herve, the "SubClassB" initializer matches the nameB > argument to 'new' to the nameB argument of the initialize method for > SubClassB. > > Simplifying the code to illustrate the problem was very helpful. It > would have been better to not present the validity methods (this might > have been a different thread), to remove the cat statements, to remove > unnecessary slots and classes (SubSubClassB1) and to name classes, > slots, and argument values in an easier to remember way (e.g., classes > A, B, C, slots a, b, c) > > Hope that helps. > > > Martin > > > ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel