On Thu, May 28, 2015 at 2:49 AM, Julien Idé <julien.ide...@gmail.com> wrote: > Hey everyone, > > I would like to develop a package using S4 classes. > I have to define several S4 classes that inherits from each others as > follow: > > # A <- B <- C <- D > > I also would like to define .DollarNames methods for these class so, if I > have understood well, I also have to define an old class as follow: > > # AOld <- A <- B <- C <- D > > setOldClass(Classes = "AOld") >
No, you don't need to define an old class for dispatching on an S3 generic. Forget the AOld and things will dispatch to .DollarNames.A just fine. That said, a few notes for posterity: First, if you're going to define an S4 class that extends an old class, you probably want to give the old class a prototype, so that calling e.g. new("A") will actually give an object that is valid for existing S3 methods on that class. Second, there seems to be a bug that breaks that strategy, because even when the old class has a prototype, it is not taken as the prototype of the extension (A). Instead, there is a plain "S4" prototype, with the class set to "Old". > setOldClass("Old", prototype=structure(list(), class="Old")) > setClass("New", contains="Old") > new("New") Object of class "New" <S4 Type Object> attr(,"class") [1] "Old" But this is still possible: > new("New", structure(list(), class="Old")) Object of class "New" An object of class "Old" Third, the fact that as(new("C"), "B") works as expected but not as(new("D"), "B") is probably also a bug. Fourth, calling setOldClass is essentially specifying a contract to which the S3 system is not bound, so it is extremely risky. If it is absolutely necessary to include an S3 object in an S4 representation, best practice is to isolate that dependency to the greatest extent possible, i.e., create an object that specifically encapsulates that S3 object, thus centralizing all of the necessary consistency checks. > setClass( > Class = "A", > contains = "AOld", > slots = list(A = "character") > ) > > .DollarNames.A <- function(x, pattern) > grep(pattern, slotNames(x), value = TRUE) > > setClass( > Class = "B", > contains = "A", > slots = list(B = "character"), > validity = function(object){ > cat("Testing an object of class '", class(object), > "'' with valitity function of class 'B'", sep = "") > cat("Validity test for class 'B': ", object@A, sep = "") > return(TRUE) > } > ) > > setClass( > Class = "C", > contains = c("B"), > slots = list(C = "character"), > validity = function(object){ > cat("Testing an object of class '", class(object), > "'' with valitity function of class 'C'", sep = "") > cat("Validity test for class 'C': ", object@A, sep = "") > return(TRUE) > } > ) > > setClass( > Class = "D", > contains = "C", > slots = list(D = "character"), > validity = function(object){ > cat("Testing an object of class '", class(object), > "'' with valitity function of class 'D'", sep = "") > cat("Validity test for class 'D': ", object@A, sep = "") > return(TRUE) > } > ) > > My problem is that when I try to create an object of class "D" and test its > validity > > validObject(new("D")) > > it seems that at some point the object is coerced to an object of class > "AOld" and tested by the validity function of class "B". What am I missing > here? > > Julien > > [[alternative HTML version deleted]] > > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel