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.