Rev 68017 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
% File src/library/methods/man/setOldClass.Rd% Part of the R package, https://www.R-project.org% Copyright 1995-2010 R Core Team% Distributed under GPL 2 or later\name{setOldClass}\alias{setOldClass}\alias{.setOldIs}\alias{POSIXct-class}\alias{POSIXlt-class}\alias{POSIXt-class}\alias{aov-class}\alias{maov-class}\alias{anova-class}\alias{anova.glm-class}\alias{anova.glm.null-class}\alias{Date-class}\alias{data.frame-class}\alias{data.frameRowLabels-class}\alias{density-class}\alias{dump.frames-class}\alias{factor-class}\alias{formula-class}\alias{glm-class}\alias{glm.null-class}\alias{hsearch-class}\alias{integrate-class}\alias{libraryIQR-class}\alias{lm-class}\alias{logLik-class}\alias{mlm-class}\alias{mtable-class}\alias{mts-class}\alias{ordered-class}\alias{packageIQR-class}\alias{packageInfo-class}\alias{recordedplot-class}\alias{rle-class}\alias{socket-class}\alias{summaryDefault-class}\alias{summary.table-class}\alias{oldClass-class}\alias{.OldClassesList}\alias{table-class}\alias{initialize,data.frame-method}\alias{initialize,factor-method}\alias{initialize,ordered-method}\alias{initialize,table-method}\alias{initialize,summary.table-method}\title{Register Old-Style (S3) Classes and Inheritance}\description{Register an old-style (a.k.a. \sQuote{S3}) class as a formally definedclass. The \code{Classes} argument is the character vector used as the\code{class} attribute; in particular, if there is more than onestring, old-style class inheritance is mimicked. Registering via\code{setOldClass} allows S3 classes to appear in method signatures,as a slot in an S4 class, or as a superclass of an S4 class.}\usage{setOldClass(Classes, prototype, where, test = FALSE, S4Class)}\arguments{\item{Classes}{A character vector, giving the names for S3classes, as they would appear on the right side of an assignment ofthe \code{class} attribute in S3 computations.In addition to S3 classes, an object type or other valid data partcan be specified, if the S3 class is known to require its data tobe of that form.}\item{prototype}{An optional object to use as the prototype. This should be providedas the default S3 object for the class. If omitted, the S4 classcreated to register the S3 class is \code{VIRTUAL}. See thedetails.}\item{where}{Where to store the class definitions, the global or top-levelenvironment by default. (When either function is called in thesource for a package, the class definitions will be included in thepackage's environment by default.)}\item{test}{flag, if \code{TRUE}, arrange to test inheritanceexplicitly for each object, needed if the S3 class can have adifferent set of class strings, with the same first string.This is a different mechanism in implementation and should bespecified separately for each pair of classes that have anoptional inheritance. See the \sQuote{Details}.}\item{S4Class}{ optionally, the class definition or the class nameof an S4 class. The new class will have all the slots and otherproperties of this class, plus its S3 inheritance as defined bythe \code{Classses} argument. Arguments \code{prototype} and\code{test} must not be supplied in this case. See the sectionon \dQuote{S3 classes with known attributes} below.}}\details{Each of the names will be defined as an S4 class, extending theremaining classes in \code{Classes}, and the class \code{oldClass},which is the \sQuote{root} of all old-style classes. S3 classes haveno formal definition, and therefore no formally defined slots. If a\code{prototype} argument is supplied in the call to\code{setOldClass()}, objects from the class can be generated, by acall to \code{\link{new}}; however, this usually not as relevant asgenerating objects from subclasses (see the section on extending S3classes below). If a prototype is not provided,the class will be created as a virtual S4 class.The main disadvantage is that the prototype object in an S4 class thatuses this class as a slot will have a \code{NULL} object in that slot,which can sometimes lead to confusion.Beginning with version 2.8.0 of \R, support is provided for using a(registered) S3 class as a superclass of a new S4 class. See thesection on extending S3 classes below, and the examples.See \link{Methods} for the details of method dispatch andinheritance.Some S3 classes cannot be represented as an ordinary combination of S4classes and superclasses, because objects from the S3 class can have avariable set of strings in the class. It is still possible to registersuch classes as S4 classes, but now the inheritance has to be verifiedfor each object, and you must call \code{setOldClass} with argument\code{test=TRUE} once for each superclass.For example, ordered factors \emph{always} have the S3class \code{c("ordered", "factor")}. This is proper behavior, andmaps simply into two S4 classes, with \code{"ordered"} extending\code{"factor"}.But objects whose class attribute has \code{"POSIXt"} as the firststring may have either (or neither) of \code{"POSIXct"} or\code{"POSIXlt"} as the second string. This behavior can be mappedinto S4 classes but now to evaluate \code{is(x, "POSIXlt")}, forexample, requires checking the S3 class attribute on each object.Supplying the \code{test=TRUE} argument to \code{setOldClass} causesan explicit test to be included in the class definitions. It'snever wrong to have this test, but since it adds significantoverhead to methods defined for the inherited classes, you shouldonly supply this argument if it's known that object-specific testsare needed.The list \code{.OldClassesList} contains the old-style classes thatare defined by the methods package. Each element of the list is acharacter vector, with multiple strings if inheritance is included.Each element of the list was passed to \code{setOldClass} whencreating the \pkg{methods} package; therefore, these classes can be usedin \code{\link{setMethod}} calls, with the inheritance as implied bythe list.}\section{Extending S3 classes}{A call to \code{setOldClass} creates formal classes correspondingto S3 classes, allows these to be used as slots in other classes or ina signature in \code{\link{setMethod}}, and mimics the S3inheritance.In documentation for the initial implementation of S4 classes in \R,users were warned against defining S4 classes that contained S3classes, even if those had been registered. The warning was basedmainly on two points. 1: The S3 behavior of the objects would failbecause the S3 class would not be visible, for example, when S3methods are dispatched. 2: Because S3 classes have no formaldefinition, nothing can be asserted in general about the S3 part ofan object from such a class. (The warning was repeated as recentlyas the first reference below.)Nevertheless, defining S4 classes to contain an S3 class and extendits behavior is attractive in many applications. The alternative isto be stuck with S3 programming, without the flexibility and security offormal class and method definitions.Beginning with version 2.8.0, \R provides support for extendingregistered S3 classes; that is, for new classes defined by a call to\code{\link{setClass}} in which the \code{contains=} argumentincludes an S3 class. See the examples below. The support is aimedprimarily at providing the S3 class information for all classes thatextend class \linkS4class{oldClass}, in particular by ensuring thatall objects from such classes contain the S3 class in a specialslot.There are three different ways to indicate an extension to an existingS3 class: \code{setOldClass()}, \code{setClass()} and\code{setIs()}. In most cases, calling \code{setOldClass} is thebest approach, but the alternatives may be preferred in the specialcircumstances described below.Suppose \code{"A"} is any class extending \code{"oldClass"}. then\code{setOldClass(c("B", "A"))}creates a new class \code{"B"} whose S3 classconcatenates \code{"B"} with \code{S3Class("A")}. The new class is avirtual class. If \code{"A"} was defined with known attribute/slots,then \code{"B"} has these slots also; therefore, you must believe thatthe corresponding S3 objects from class \code{"B"} do indeed have theclaimed attributes. Notice that you can supply an S4 definition for thenew class to specify additional attributes (as described in the nextsection.)The first alternative call produces a non-virtual class.\code{setClass("B", contains = "A")}This creates a non-virtual class with the same slots and superclassesas class \code{"A"}. However, class \code{"B"} is not included inthe S3 class slot of the new class, unless you provide it explicitlyin the prototype.\code{setClass("B"); setIs("B", "A", .....)}This creates a virtual class that extends \code{"A"}, but does notcontain the slots of \code{"A"}. The additional arguments to\code{\link{setIs}} should provide a coerce and replacement method.In order for the new class to inherit S3 methods, the coerce method mustensure that the class \code{"A"} object produced has a suitable S3class. The only likely reason to prefer this third approach is thatclass \code{"B"} is not consistent with known attributes in class\code{"A"}.Beginning with version 2.9.0 of \R, objects from a class extending anS3 class will be converted to the corresponding S3 class when beingpassed to an S3 method defined for that class (that is, for one of thestrings in the S3 class attribute). This is intended to ensure, asfar as possible, that such methods will work if they work for ordinaryS3 objects. See \code{\link{Classes}} for details.}\section{S3 Classes with known attributes}{A further specification of an S3 class can be made \emph{if} theclass is guaranteed to have some attributes of known class (where aswith slots, \dQuote{known} means that the attribute is an object ofa specified class, or a subclass of that class).In this case, the call to \code{setOldClass()} can supply an S4 classdefinition representing the known structure. Since S4 slots areimplemented as attributes (largely for just this reason), the knowattributes can be specified in the representation of the S4 class.The usual technique will be to create an S4 class with the desiredstructure, and then supply the class name or definition as theargument \code{S4Class} to \code{setOldClass()}.See the definition of class \code{"ts"} in the examples below. Thecall to \code{\link{setClass}} to create the S4 class can use the sameclass name, as here, so long as the class definition is not sealed.In the example, we define \code{"ts"} as a vector structure with anumeric slot for \code{"tsp"}. The validity of this definition relieson an assertion that all the S3 code for this class is consistent withthat definition; specifically, that all \code{"ts"} objects willbehave as vector structures and will have a numeric \code{"tsp"}attribute. We believe this to be true of all the base code in \R, butas always with S3 classes, no guarantee is possible.The S4 class definition can have virtual superclasses (as inthe \code{"ts"} case) if the S3 class is asserted to behaveconsistently with these (in the example, time-series objects areasserted to be consistent with the \linkS4class{structure} class).For another example, look at the S4 class definition for \code{"data.frame"}.Be warned that failures of the S3 class to live up to its assertedbehavior will usually go uncorrected, since S3 classes inherentlyhave no definition, and the resulting invalid S4 objects can causeall sorts of grief. Many S3 classes are not candidates for knownslots, either because the presence or class of the attributes arenot guaranteed (e.g., \code{dimnames} in arrays, although these arenot even S3 classes), or because the class uses named components ofa list rather than attributes (e.g., \code{"lm"}). An attributethat is sometimes missing cannot be represented as a slot, not evenby pretending that it is present with class \code{"NULL"}, becauseattributes unlike slots can not have value \code{NULL}.One irregularity that is usually tolerated, however, is to optionallyadd other attributes to those guaranteed to exist (for example,\code{"terms"} in \code{"data.frame"} objects returned by\code{\link{model.frame}}). As of version 2.8.0, validity checks by\code{\link{validObject}} ignore extra attributes; even if this checkis tightened in the future, classes extending S3 classes would likelybe exempted because extra attributes are so common.}\seealso{\code{\link{setClass}}, \code{\link{setMethod}}}\references{Chambers, John M. (2008)\emph{Software for Data Analysis: Programming with R}Springer. (For the R version: see section 10.6 for methodselection and section 13.4 for generic functions).Chambers, John M. (1998)\emph{Programming with Data}Springer (For the original S4 version.)}\examples{require(stats)setOldClass(c("mlm", "lm"))setGeneric("dfResidual", function(model)standardGeneric("dfResidual"))setMethod("dfResidual", "lm", function(model)model$df.residual)## dfResidual will work on mlm objects as well as lm objectsmyData <- data.frame(time = 1:10, y = (1:10)^.5)myLm <- lm(cbind(y, y^3) ~ time, myData)showClass("data.frame")# to see the predefined S4 "oldClass"## two examples extending S3 class "lm", class "xlm" directly## and "ylm" indirectlysetClass("xlm", representation(eps = "numeric"), contains = "lm")setClass("ylm", representation(header = "character"), contains = "xlm")ym1 = new("ylm", myLm, header = "Example", eps = 0.)## for more examples, see ?\link{S3Class}.utils::str(.OldClassesList)\dontshow{stopifnot(identical(dfResidual(myLm), myLm$df.residual))removeClass("ylm"); removeClass("xlm")rm(myData, myLm)removeGeneric("dfResidual")}## Examples of S3 classes with guaranteed attributes## an S3 class "stamped" with a vector and a "date" attribute## Here is a generator function and an S3 print method.## NOTE: it's essential that the generator checks the attribute classesstamped <- function(x, date = Sys.time()) {if(!inherits(date, "POSIXt"))stop("bad date argument")if(!is.vector(x))stop("x must be a vector")attr(x, "date") <- dateclass(x) <- "stamped"x}print.stamped <- function(x, ...) {print(as.vector(x))cat("Date: ", format(attr(x,"date")), "\n")}## Now, an S4 class with the same structure:setClass("stamped4", contains = "vector", representation(date = "POSIXt"))## We can use the S4 class to register "stamped", with its attributes:setOldClass("stamped", S4Class = "stamped4")selectMethod("show", "stamped")## and then remove "stamped4" to clean upremoveClass("stamped4")\dontshow{set.seed(113)}someLetters <- stamped(sample(letters, 10),ISOdatetime(2008, 10, 15, 12, 0, 0))st <- new("stamped", someLetters)st# show() method prints the object's class, then calls the S3 print method.stopifnot(identical(S3Part(st, TRUE), someLetters))# creating the S4 object directly from its data part and slotsnew("stamped", 1:10, date = ISOdatetime(1976, 5, 5, 15, 10, 0))\dontrun{## The code in R that defines "ts" as an S4 classsetClass("ts", contains = "structure",representation(tsp = "numeric"),prototype(NA, tsp = rep(1,3)))# prototype to be a legal S3 time-series## and now registers it as an S3 classsetOldClass("ts", S4Class = "ts", where = envir)}\dontshow{removeClass("stamped")rm(someLetters, st)}}\keyword{ programming }\keyword{ methods }