Classes {methods} | R Documentation |
Class Definitions
Description
Class definitions are objects that contain the formal definition of a
class of R objects, usually referred to as an S4 class, to
distinguish them from the informal S3 classes.
This document gives an overview of S4 classes; for
details of the class representation objects, see help for the class
classRepresentation
.
Metadata Information
When a class is defined, an object is stored that contains the
information about that class. The object, known as the
metadata defining the class, is not stored under the name of
the class (to allow programmers to write generating functions of
that name), but under a specially constructed name.
To examine the class definition, call getClass
. The
information in the metadata object includes:
- Slots:
-
The data contained in an object from an S4 class is defined by the slots in the class definition.
Each slot in an object is a component of the object; like components (that is, elements) of a list, these may be extracted and set, using the function
slot()
or more often the operator"@"
. However, they differ from list components in important ways. First, slots can only be referred to by name, not by position, and there is no partial matching of names as with list elements.All the objects from a particular class have the same set of slot names; specifically, the slot names that are contained in the class definition. Each slot in each object always is an object of the class specified for this slot in the definition of the current class. The word “is” corresponds to the R function of the same name (
is
), meaning that the class of the object in the slot must be the same as the class specified in the definition, or some class that extends the one in the definition (a subclass).One slot name is special,
.Data
. This stands for the ‘data part’ of the object. An object from a class with a data part is defined by specifying that the class contains one of the R object types or one of the special pseudo-classes,matrix
orarray
, usually because the definition of the class, or of one of its superclasses, has included the type or pseudo-class in itscontains
argument. See the section on inheriting from non-S4 classes for more details. - Superclasses:
-
The definition of a class includes the superclasses —the classes that this class extends. A class
Fancy
, say, extends a classSimple
if an object from theFancy
class has all the capabilities of theSimple
class (and probably some more as well). In particular, and very usefully, any method defined to work for aSimple
object can be applied to aFancy
object as well.This relationship is expressed equivalently by saying that
Simple
is a superclass ofFancy
, or thatFancy
is a subclass ofSimple
.The direct superclasses of a class are those superclasses explicitly defined. Direct superclasses can be defined in three ways. Most commonly, the superclasses are listed in the
contains=
argument in the call tosetClass
that creates the subclass. In this case the subclass will contain all the slots of the superclass, and the relation between the class is called simple, as it in fact is. Superclasses can also be defined explicitly by a call tosetIs
; in this case, the relation requires methods to be specified to go from subclass to superclass. Thirdly, a class union is a superclass of all the members of the union. In this case too the relation is simple, but notice that the relation is defined when the superclass is created, not when the subclass is created as with thecontains=
mechanism.The definition of a superclass will also potentially contain its own direct superclasses. These are considered (and shown) as superclasses at distance 2 from the original class; their direct superclasses are at distance 3, and so on. All these are legitimate superclasses for purposes such as method selection.
When superclasses are defined by including the names of superclasses in the
contains=
argument tosetClass
, an object from the class will have all the slots defined for its own class and all the slots defined for all its superclasses as well.The information about the relation between a class and a particular superclass is encoded as an object of class
SClassExtension
. A list of such objects for the superclasses (and sometimes for the subclasses) is included in the metadata object defining the class. If you need to compute with these objects (for example, to compare the distances), call the functionextends
with argumentfullInfo=TRUE
. - Prototype:
-
The objects from a class created by a call to
new
are defined by the prototype object for the class and by additional arguments in the call tonew
, which are passed to a method for that class for the functioninitialize
.Each class representation object contains a prototype object for the class (although for a virtual class the prototype may be
NULL
). The prototype object must have values for all the slots of the class. By default, these are the prototypes of the corresponding slot classes. However, the definition of the class can specify any valid object for any of the slots.
Virtual classes; Basic classes
Classes exist for which no actual objects can be created by a
call to new
, the
virtual classes, in fact a
very important programming tool. They are used to group together
ordinary classes that want to share some programming behavior,
without necessarily restricting how the behavior is implemented.
Virtual class definitions may if you want include
slots (to provide some common behavior without fully defining
the object—see the class traceable
for an example).
A simple and useful form of virtual class is the class
union, a virtual class that is defined in a call to
setClassUnion
by listing one or
more of subclasses (classes that extend the class union). Class
unions can include as subclasses basic object types (whose
definition is otherwise sealed).
There are a number of ‘basic’ classes, corresponding to the
ordinary kinds of data occurring in R. For example,
"numeric"
is a class corresponding to numeric vectors.
The other vector basic classes are "logical"
, "integer"
,
"complex"
, "character"
, "raw"
, "list"
and "expression"
.
The prototypes for
the vector classes are vectors of length 0 of the corresponding
type. Notice that basic classes are unusual in that the
prototype object is from the class itself.
In addition to the vector classes there are also basic classes corresponding to objects in the
language, such as "function"
and "call"
.
These classes are subclasses of the virtual class "language"
.
Finally, there are object types and corresponding basic classes for
“abnormal” objects, such as "environment"
and
"externalptr"
.
These objects do not follow the
functional behavior of the language; in particular, they are not
copied and so cannot have attributes or slots defined locally.
All these classes can be used as slots or as superclasses for any other class definitions, although they do not themselves come with an explicit class. For the abnormal object types, a special mechanism is used to enable inheritance as described below.
Inheriting from non-S4 Classes
A class definition can extend classes other than
regular S4 classes, usually by specifying them in the
contains=
argument to setClass
. Three groups
of such classes behave distinctly:
-
S3 classes, which must have been registered by a previous call to
setOldClass
(you can check that this has been done by callinggetClass
, which should return a class that extends oldClass); -
One of the R object types, typically a vector type, which then defines the type of the S4 objects, but also a type such as
environment
that can not be used directly as a type for an S4 object. See below. -
One of the pseudo-classes
matrix
andarray
, implying objects with arbitrary vector types plus thedim
anddimnames
attributes.
This section describes the approach to combining S4 computations with older S3 computations by using such classes as superclasses. The design goal is to allow the S4 class to inherit S3 methods and default computations in as consistent a form as possible.
As part of a general effort to make the S4 and S3 code in R more
consistent,
when objects from an S4 class are used as the first argument
to a non-default S3 method, either for an S3 generic function (one that calls
UseMethod
) or for one of the primitive functions
that dispatches S3 methods, an effort is made to provide a
valid object for that method. In
particular, if the S4 class extends an S3 class or matrix
or array
, and there is an S3 method matching one of these
classes, the S4 object will be coerced to a valid S3 object, to
the extent that is possible given that there is no formal
definition of an S3 class.
For example, suppose "myFrame"
is an S4 class that
includes the S3 class "data.frame"
in the contains=
argument to setClass
. If an object from this S4
class is passed to a function, say as.matrix
, that
has an S3 method for "data.frame"
, the internal code for
UseMethod
will convert the object to a data frame;
in particular, to an S3 object whose class attribute will be the vector
corresponding to the S3 class (possibly containing multiple
class names). Similarly for an S4 object inheriting from
"matrix"
or "array"
, the S4 object will be
converted to a valid S3 matrix or array.
Note that the conversion is not applied when an S4 object is passed
to the default S3 method. Some S3 generics attempt
to deal with general objects, including S4 objects. Also, no transformation is
applied to S4 objects that do not correspond to a
selected S3 method; in particular, to objects from a class that
does not contain either an S3 class or one of the basic types.
See asS4
for the transformation details.
In addition to explicit S3 generic functions, S3 methods are defined for a variety of operators and functions implemented as primitives. These methods are dispatched by some internal C code that operates partly through the same code as real S3 generic functions and partly via special considerations (for example, both arguments to a binary operator are examined when looking for methods). The same mechanism for adapting S4 objects to S3 methods has been applied to these computations as well, with a few exceptions such as generating an error if an S4 object that does not extend an appropriate S3 class or type is passed to a binary operator.
The remainder of this section discusses the mechanisms for
accessing the inherited objects of the second and third items
above: basic object types and the matrix and array
pseudo-classes. For the corresponding details for inheritance
from S3 classes, see setOldClass
.
An object from a class that directly and simply contains one
of the basic object types in R, has implicitly a corresponding
.Data
slot of that type, allowing computations to extract
or replace the data part while leaving other slots
unchanged. If the type is one that can accept attributes and is
duplicated normally, the inheritance also determines the type of the
object; if the class definition has a .Data
slot
corresponding to a normal type, the class of the
slot determines the type of the object (that is, the value of
typeof(x)
).
For such classes, .Data
is a pseudo-slot; that
is, extracting or setting it modifies the non-slot data in the
object. The functions getDataPart
and
setDataPart
are a cleaner, but essentially
equivalent way to deal with the data part.
Extending a basic type this way allows objects to
use old-style code for the corresponding type as well as S4
methods. Any basic type can be used for .Data
, but
a few types are treated differently because they do not behave like ordinary objects;
for example, "NULL"
, environments, and external pointers.
Classes extend these types by using a specially named slot,
itself inherited from an internally defined S4 class.
Inheritance from the nonstandard object type then requires an
actual computation, rather than the "simple"
inclusion
for other types and classes. The intent is that programmers
will not need to take account of the mechanism, but one
implication is that you should not explicitly use the
type of an S4 object that extends an arbitrary object type. Use
is
and similar functions instead.
There is one additional use of the data part, which is also an
exception to the correspondence with the object's type. The exception
arises from the special treatment of matrix
and array
“classes” in R.
Matrix and array objects are managed internally and recognized
without regard to any class attribute; therefore, they can be
used as the data part of a new class. In this case, the object
type for the new class depends on the type of the data in the
matrix or array, but the .Data
slot in the definition
will be "matrix"
or "array"
.
References
Chambers, John M. (2008) Software for Data Analysis: Programming with R Springer. (For the R version.)
Chambers, John M. (1998) Programming with Data Springer (For the original S4 version.)
Chambers, John M. and Hastie, Trevor J. eds (1992) Statistical Models in S. Wadsworth & Brooks/Cole (Appendix A for S3 classes.)
Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) The New S Language. Wadsworth & Brooks/Cole. (Out of print.) (The description of vectors, matrix, array and time-series objects.)
See Also
Methods
for analogous discussion of methods,
setClass
for details of specifying class definitions,
is
,
as
,
new
,
slot