setOldClass {methods} | R Documentation |
Register Old-Style (S3) Classes and Inheritance
Description
Register an old-style (a.k.a. ‘S3’) class as a formally defined class. Simple usage will be of the form:
setOldClass(Classes)
where Classes
is the character vector that would be the
class
attribute of the S3 object. Calls to
setOldClass()
in the code for a package
allow the class to be used as a slot in formal (S4) classes and in
signatures for methods (see Methods_for_S3).
Formal classes can also contain a registered S3 class (see
S3Part for details).
If the S3 class has a known set of attributes, an
equivalent S4 class can be specified by S4Class=
in the call to
setOldClass()
; see the section “Known Attributes”.
Usage
setOldClass(Classes, prototype, where, test = FALSE, S4Class)
Arguments
Classes |
A character vector, giving the names for S3
classes, as they would appear on the right side of an assignment of
the In addition to S3 classes, an object type or other valid data part can be specified, if the S3 class is known to require its data to be of that form. |
S4Class |
optionally, the class definition or the class name
of an S4 class. The new class will have all the slots and other
properties of this class, plus any S3 inheritance implied by
multiple names in the |
prototype , where , test |
These arguments are currently allowed, but not recommended in typical applications.
|
Details
The name (or each of the names) in Classes
will be defined as an S4 class, extending class oldClass
,
which is the ‘root’ of all old-style classes. S3 classes
with multiple names in their class attribute will have a
corresponding inheritance as formal classes. See the "mlm"
example.
S3 classes have
no formal definition, and therefore no formally defined slots.
If no S4 class is supplied as a model, the class created will be a
virtual class.
If a virtual class (any virtual class) is used for a slot in another class, then the
initializing method for the class needs to put something legal in
that slot; otherwise it will be set to NULL
.
See Methods_for_S3 for the details of method dispatch and inheritance with mixed S3 and S4 methods.
Some S3 classes cannot be represented as an ordinary combination of S4
classes and superclasses, because objects with the same initial
string in the class attribute can have different strings following.
Such classes are fortunately rare. They violate the basic idea of
object-oriented programming and should be avoided.
If you must deal with them, it is still possible to register
such classes as S4 classes, but now the inheritance has to be verified
for each object, and you must call setOldClass
with argument
test=TRUE
.
Pre-Defined Old Classes
Many of the widely used S3 classes in the standard R distribution come pre-defined for use with S4. These don't need to be explicitly declared in your package (although it does no harm to do so).
The list .OldClassesList
contains the old-style classes that
are defined by the methods package. Each element of the list is a
character vector, with multiple strings if inheritance is included.
Each element of the list was passed to setOldClass
when
creating the methods package; therefore, these classes can be used
in setMethod
calls, with the inheritance as implied by
the list.
S3 Classes with known attributes
A further specification of an S3 class can be made if the class is guaranteed to have some attributes of known class (where as with slots, “known” means that the attribute is an object of a specified class, or a subclass of that class).
In this case, the call to setOldClass()
can supply an S4 class
definition representing the known structure. Since S4 slots are
implemented as attributes (largely for just this reason), the known
attributes can be specified in the representation of the S4 class.
The usual technique will be to create an S4 class with the desired
structure, and then supply the class name or definition as the
argument S4Class=
to setOldClass()
.
See the definition of class "ts"
in the examples below and
the data.frame
example in Section 10.2 of the reference.
The call to setClass
to create the S4 class can use the same
class name, as here, so long as the call to setOldClass
follows in the same package. For clarity it should be the next
expression in the same file.
In the example, we define "ts"
as a vector structure with a
numeric slot for "tsp"
. The validity of this definition relies
on an assertion that all the S3 code for this class is consistent with
that definition; specifically, that all "ts"
objects will
behave as vector structures and will have a numeric "tsp"
attribute. We believe this to be true of all the base code in R, but
as always with S3 classes, no guarantee is possible.
The S4 class definition can have virtual superclasses (as in
the "ts"
case) if the S3 class is asserted to behave
consistently with these (in the example, time-series objects are
asserted to be consistent with the structure class).
Failures of the S3 class to live up to its asserted
behavior will usually go uncorrected, since S3 classes inherently
have no definition, and the resulting invalid S4 objects can cause
all sorts of grief. Many S3 classes are not candidates for known
slots, either because the presence or class of the attributes are
not guaranteed (e.g., dimnames
in arrays, although these are
not even S3 classes), or because the class uses named components of
a list rather than attributes (e.g., "lm"
). An attribute
that is sometimes missing cannot be represented as a slot, not even
by pretending that it is present with class "NULL"
, because
attributes, unlike slots, can not have value NULL
.
One irregularity that is usually tolerated, however, is to optionally
add other attributes to those guaranteed to exist (for example,
"terms"
in "data.frame"
objects returned by
model.frame
). Validity checks by
validObject
ignore extra attributes; even if this check
is tightened in the future, classes extending S3 classes would likely
be exempted because extra attributes are so common.
References
Chambers, John M. (2016) Extending R, Chapman & Hall. (Chapters 9 and 10, particularly Section 10.8)
See Also
Examples
require(stats)
## "lm" and "mlm" are predefined; if they were not this would do it:
## Not run:
setOldClass(c("mlm", "lm"))
## End(Not run)
## Define a new generic function to compute the residual degrees of freedom
setGeneric("dfResidual",
function(model) stop(gettextf(
"This function only works for fitted model objects, not class %s",
class(model))))
setMethod("dfResidual", "lm", function(model)model$df.residual)
## dfResidual will work on mlm objects as well as lm objects
myData <- data.frame(time = 1:10, y = (1:10)^.5)
myLm <- lm(cbind(y, y^3) ~ time, myData)
## two examples extending S3 class "lm": class "xlm" directly
## and "ylm" indirectly
setClass("xlm", slots = c(eps = "numeric"), contains = "lm")
setClass("ylm", slots = c(header = "character"), contains = "xlm")
ym1 = new("ylm", myLm, header = "Example", eps = 0.)
## for more examples, see ?\link{S3Class}.
## Not run:
## The code in R that defines "ts" as an S4 class
setClass("ts", contains = "structure", slots = c(tsp = "numeric"),
prototype(NA, tsp = rep(1,3)))
# prototype to be a legal S3 time-series
## and now registers it as an S3 class
setOldClass("ts", S4Class = "ts", where = envir)
## End(Not run)