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

Reply via email to