Hi all, I am having trouble extending S4 classes in cases where I'm using both validity and initialize methods. I've read as much S4 information as I can find, but I've yet to have that "a-ha" moment.
In my application, I am using validity methods to guard against inappropriate input data that my code has no way of handling, and initialize methods to detect and deal with fixable problems. As a toy example, consider classes A and B and associated methods as defined below. I use a validity method for A to complain about negative values, and an initialize method to "correct" small input values. B should simply extend A by adding an extra slot. The example is contrived, but it illustrates a key behavior that I also encounter in my real code: setClass("A", representation(x="numeric")) setClass("B", representation(y="character"), contains="A") setValidity("A", function(object) { message("start validate A") retval <- NULL if (any([EMAIL PROTECTED]<0)) retval <- c(retval, "x must be positive") message("done validate A") if(is.null(retval)) return(TRUE) else return(retval) }) setMethod("initialize", "A", function(.Object, ...) { message("start init A") .Object <- callNextMethod() x <- [EMAIL PROTECTED] [EMAIL PROTECTED] <- ifelse(log(x)<0, 1, x) message("done init A") .Object }) setMethod("initialize", "B", function(.Object, ...) { message("start init B") callNextMethod() }) # Creating an instance of A works just as I would expect > a <- new("A", x=c(0.5, 2)) start init A start validate A done validate A done init A > a An object of class “A” Slot "x": [1] 1 2 # But subsequently creating a derived B object fails! > new("B", a, y="foo") start init B start init A start validate A start init A Error in checkSlotAssignment(object, name, value) : assignment of an object of class "logical" is not valid for slot "x" in an object of class "A"; is(value, "numeric") is not TRUE The two things I haven't quite figured out are: 1. Why is initialize invoked *twice* for A during instantiation of B? 2. The second time initialize is invoked for A, it appears [EMAIL PROTECTED] is only bound to its implicit prototype value of numeric(0). Why? Of course, this leads to an error because the ifelse expression subsequently evaluates to logical(0) rather than a numeric vector as intended. Again, this is a contrived example, but a very real problem in my code. I suppose I could define a prototype for A that I know won't break my initialize method, but that seems inelegant and hard to maintain. Is there a better way to code this so that I can reliably instantiate B using a valid A object? Hopefully I've just got something wrong in the formals for my initialize methods or in my use of getNextMethod(), but I've had no luck trying some alternatives -- and ultimately I'd prefer to better understand the underlying behavior rather than stumble onto something that merely appears to work. I'd be grateful for any suggestions... Thanks, Jim ------------------------------ James Regetz, Ph.D. Scientific Programmer/Analyst National Center for Ecological Analysis & Synthesis 735 State St, Suite 300 Santa Barbara, CA 93101 ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel