In this method... setMethod("initialize", "baseClass", function(.Object, ...) { print("---initialize:baseClass---") # .Object <- callNextMethod(); strg <- [EMAIL PROTECTED]; print(paste("base:strg = ", strg)) if (strg == "") { [EMAIL PROTECTED] <- as.character(getwd()); }#if if (substr(strg, nchar(strg), nchar(strg)) == "/") { [EMAIL PROTECTED] <- substr(strg, 0, nchar(strg)-1); }#if print(paste("base:mydir = ", [EMAIL PROTECTED])) .Object <- callNextMethod(); .Object; } )#initialize
the argument '...' includes the argument mydir="". Later, when you .Object <- callNextMethod(), it invokes the 'next' method with the same argument, i.e., with mydir="". This causes the 'mydir' slot to be initialized with "", triggering the validity error. You can see this more clearly in the following, where the provided argument x=10:1 overrides the assignment in initialize: > setClass("A", representation=representation(x="numeric")) [1] "A" > setMethod("initialize", "A", + function(.Object, ...) { + [EMAIL PROTECTED] <- 1:10 + callNextMethod() + }) [1] "initialize" > new("A", x=10:1) An object of class "A" Slot "x": [1] 10 9 8 7 6 5 4 3 2 1 One solution is to name any arguments you're going to manipulate in the initialize method, and then make sure the correct arguments are passed to callNextMethod. You'll probably want to provide a sensible default argument to mydir, so that user doesn't have to do anything clever (like remember to pass "") to get the default behavior. Here's what I end up with: setMethod("initialize", "baseClass", function(.Object, mydir=as.character(getwd()), ...) { if (substr(mydir, nchar(mydir), nchar(mydir)) == "/") { mydir <- substr(mydir, 0, nchar(mydir)-1) } callNextMethod(.Object, mydir=mydir, ...); }) setMethod("initialize", "derivedClass", function(.Object, mytitle="MyTitle", ...) { callNextMethod(.Object, mytitle=mytitle, ...) }) Another solution is to follow the convention where callNextMethod() comes first (constructing a valid object!), and your initialize method then fills in slots with the appropriate values. One interesting part of your example is that new('derivedClass') does NOT cause a validity error, even though the object is invalid ('myname' is ""; also, none of your validity method messages are printed)! Apparently, the assumption is that you (the programmer, as opposed to the user) are not going to create an invalid object by default. Also, take a look at the initialize method that R has constructed for derivedClass: > getMethod("initialize", "derivedClass") Method Definition: function (.Object, ...) { .local <- function (.Object, mytitle = "MyTitle", ...) { callNextMethod(.Object, mytitle = mytitle, ...) } .local(.Object, ...) } Signatures: .Object target "derivedClass" defined "derivedClass" Notice how the function is defined in terms of .Object and .... The named arguments not present in the generic signature (i.e., 'mytitle') are 'hidden' in the .local function definition. By the time callNextMethod() has been evaluated, '...' does NOT include 'mytitle'. I think this is why you must explicitly include any named arguments you want to pass to callNextMethod -- the default is to callNextMethod with the generic signature, but with symbols (.Object, ...) taking their current value. Here's a simpler illustration: setClass("A", representation=representation(x="numeric")) setMethod("initialize", "A", function(.Object, x, ...) callNextMethod()) This leads to the perhaps unexpected outcome > new("A", x=10:1) An object of class "A" Slot "x": numeric(0) I say unexpected because, if there was no initialize method, or if the initialize method were written without 'x' in the signature, then the argument 'x' would be used to fill the slot:x. Here's the solution like that for baseClass, above: setMethod("initialize", "A", function(.Object, x, ...) callNextMethod(.Object, x=x, ...)) ...which leads to > new("A", x=10:1) An object of class "A" Slot "x": [1] 10 9 8 7 6 5 4 3 2 1 Hope that helps, Martin cstrato <[EMAIL PROTECTED]> writes: > Dear Seth > > Thank you for your comments. Please see my comments and at the end my > corrected code and output. > Sorrowly, the problem remains the same. > > Seth Falcon wrote: >> cstrato <[EMAIL PROTECTED]> writes: >> >> >>> Dear all, >>> >>> Maybe, I am doing something wrong, but using R-2.5.0 on my Intel-Mac, I >>> have problems >>> using function callNextMethod() in method initialize. >>> >>> I am loading the following code as file "testS4.R": >>> >> >> I don't think this is the code in the same state as that which you ran >> the examples. Did you add/remove some comment lines perhaps? >> >> After copy/pasting the code you posted, I get: >> >> > tmp<-new("derivedClass") >> [1] "---initialize:derivedClass---" >> [1] "mytitle = MyTitle" >> > tmp<-new("derivedClass",myname="testname",mytitle="testitle") >> [1] "---initialize:derivedClass---" >> [1] "mytitle = MyTitle" >> >> > I am sorry, you are correct, I have commented out ".Object <- > callNextMethod()" in method > initialize for derivedClass afterwards. >>> setValidity("baseClass", >>> function(object) { >>> print("---setValidity:baseClass---") >>> strg <- [EMAIL PROTECTED]; >>> if (!(is(strg, "character") && nchar(strg) > 0)) { >>> warning(paste(sQuote("myname"), "is missing")); >>> }#if >>> print(paste("myname = ",[EMAIL PROTECTED])) >>> strg <- [EMAIL PROTECTED]; >>> if (!(is(strg, "character") && file.exists(strg))) { >>> warning(paste(sQuote("mydir"), "is not a system directory")); >>> }#if >>> if (substr(strg, nchar(strg), nchar(strg)) == "/") { >>> [EMAIL PROTECTED] <- substr(strg, 0, nchar(strg)-1); >>> }#if >>> print(paste("mydir = ",[EMAIL PROTECTED])) >>> } >>> )#setValidity >>> >> >> Your validity function isn't valid :-P It should either return TRUE or >> return a character vector describing what isn't valid about the >> object. Don't call warning() or print(). >> > Please see my corrected code where I use "validMsg()" from BioBase. >> Also, you don't need those ';' >> >> And finally, you are operating on a _copy_ in the validity method >> (just like everywhere else) and so this >> >> >>> if (substr(strg, nchar(strg), nchar(strg)) == "/") { >>> [EMAIL PROTECTED] <- substr(strg, 0, nchar(strg)-1); >>> }#if >>> >> >> will not have any effect on the instance passed in. It is an odd >> thing to do in a validity method. >> > You are right, I moved this code to method "initialize". >> + seth >> >> > Here is my new code "testS4.R" (as used in the output): > > setClass("baseClass", > representation(myname = "character", > mydir = "character", > "VIRTUAL"), > prototype(myname = "", > mydir = "") > )#baseClass > > setClass("derivedClass", > representation(mytitle = "character"), > contains=c("baseClass"), > prototype(mytitle = "") > )#derivedClass > > # taken from package BioBase: tools.R > validMsg <- function(msg, result) { > if (is.character(result)) { > append(msg, result); > } else { > msg; > }#if > } > > setMethod("initialize", "baseClass", > function(.Object, ...) { > print("---initialize:baseClass---") > # .Object <- callNextMethod(); > strg <- [EMAIL PROTECTED]; > print(paste("base:strg = ", strg)) > if (strg == "") { > [EMAIL PROTECTED] <- as.character(getwd()); > }#if > if (substr(strg, nchar(strg), nchar(strg)) == "/") { > [EMAIL PROTECTED] <- substr(strg, 0, nchar(strg)-1); > }#if > print(paste("base:mydir = ", [EMAIL PROTECTED])) > .Object <- callNextMethod(); > .Object; > } > )#initialize > > setValidity("baseClass", > function(object) { > print("---setValidity:baseClass---") > msg <- NULL; > strg <- [EMAIL PROTECTED]; > if (!(is(strg, "character") && nchar(strg) > 0)) { > msg <- validMsg(msg, paste(sQuote("myname"), "is missing")); > }#if > print(paste("base:myname = ",[EMAIL PROTECTED])) > strg <- [EMAIL PROTECTED]; > if (!(is(strg, "character") && file.exists(strg))) { > msg <- validMsg(msg, paste(sQuote("mydir"), "is not a system > directory")); > }#if > print(paste("base:mydir = ",[EMAIL PROTECTED])) > if (is.null(msg)) TRUE else msg; > } > )#setValidity > > setMethod("initialize", "derivedClass", > function(.Object, ...) { > print("---initialize:derivedClass---") > # .Object <- callNextMethod(); > if ([EMAIL PROTECTED] == "") { > [EMAIL PROTECTED] = "MyTitle"; > }#if > print(paste("derived:mytitle = ",[EMAIL PROTECTED])) > .Object <- callNextMethod(); > .Object; > } > )#initialize > > setValidity("derivedClass", > function(object) { > print("---setValidity:derivedClass---") > msg <- NULL; > strg <- [EMAIL PROTECTED]; > if (!(is(strg, "character") && nchar(strg) > 0)) { > msg <- validMsg(msg, paste(sQuote("mytitle"), "is missing")); > }#if > print(paste("derived:mytitle = ",[EMAIL PROTECTED])) > if (is.null(msg)) TRUE else msg; > } > )#setValidity > > > Here is the new output with the same error: > > > library(methods) > > source("testS4.R") > > tmp<-new("derivedClass") > [1] "---initialize:derivedClass---" > [1] "derived:mytitle = MyTitle" > [1] "---initialize:baseClass---" > [1] "base:strg = " > [1] "base:mydir = /Volumes/CoreData/CRAN/Workspaces/tests" > > > > tmp<-new("derivedClass",myname="testname",mydir="",mytitle="testitle") > [1] "---initialize:derivedClass---" > [1] "derived:mytitle = MyTitle" > [1] "---initialize:baseClass---" > [1] "base:strg = " > [1] "base:mydir = /Volumes/CoreData/CRAN/Workspaces/tests" > [1] "---setValidity:baseClass---" > [1] "base:myname = testname" > [1] "base:mydir = " > Error in validObject(.Object) : invalid class "derivedClass" object: > 'mydir' is not a system directory > > I do not understand why "mydir" is not recognized correctly? > > Thank you > Christian > > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel -- Martin Morgan Bioconductor / Computational Biology http://bioconductor.org ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel