S3Part {methods} | R Documentation |
Old-style (S3) classes may be registered as S4 classes (by calling
setOldClass
, and many have been. These classes can
then be contained in (that is, superclasses of) regular S4 classes, allowing formal methods
and slots to be added to the S3 behavior. The function
S3Part
extracts or replaces
the S3 part of such an object and S3Class
extracts or
replaces the S3-style class. Most computations that need to deal with the S3
aspects can coerce the objects automatically, without direct calls
to these functions. The functions also work for classes that extend
basic vector or matrix object types. See the details below.
Also discussed are S3 <-> S4 coercion; see the section “S3 and S4 objects”
S3Part(object, strictS3 = FALSE, S3Class)
S3Part(object, strictS3 = FALSE, needClass = ) <- value
S3Class(object)
S3Class(object) <- value
isXS3Class(classDef)
slotsFromS3(object)
object |
An object from some class that extends a registered
S3 class,
usually because the class has as
one of its superclasses an S3 class registered by a call to
For most of the functions, an S3 object can also be supplied, with the interpretation that it is its own S3 part. |
strictS3 |
If |
S3Class |
The character vector to be stored as the S3 class
slot in the object returned. Usually, and by default, retains
the slot from |
needClass |
Require that the replacement value be this class or a subclass of it. |
value |
For For |
classDef |
A class definition object, as returned by |
Classes that register S3 classes by a call to
setOldClass
have slot ".S3Class"
to hold
the corresponding S3 vector of class strings.
The prototype of such
a class has the value for this slot determined by the argument to
setOldClass
.
As a result, new S4 classes that extend (contain) such registered S3
classes also have the same slot, and by default the prototype has
the value determined by the contains=
argument to
setClass
.
Individual objects from the S4 class may
have
an S3 class corresponding to the value in the prototype or to an
(S3) subclass of that value. See the examples below.
S3Part()
with strictS3 = TRUE
constructs the underlying S3 object by eliminating
all the formally defined slots and turning off the S4 bit of the
object. With strictS3 = FALSE
the object returned is from
the corresponding S4 class. For consistency and generality,
S3Part()
works also for classes that extend the basic vector,
matrix and array classes. Since R is somewhat arbitrary about what
it treats as an S3 class ("ts"
is, but "matrix"
is
not), S3Part()
tries to return an S3 (that is, non-S4) object
whenever the S4 class has a suitable superclass, of either S3 or
basic object type.
One general application that relies on this generality is to use
S3Part()
to get a superclass object that is guaranteed not to
be an S4 object. If you are calling some function that checks for
S4 objects, you need to be careful not to end up in a closed loop
(fooS4
calls fooS3
, which checks for an S4 object and
calls fooS4
again, maybe indirectly). Using S3Part()
with strictS3 = TRUE
is a mechanism to avoid such loops.
Because the contents of S3 class objects have no definition or guarantee, the computations involving S3 parts do not| check for slot validity. Slots are implemented internally in R as attributes, which are copied when present in the S3 part. For this reason, grave problems can occur if an S4 class extending an S3 class uses the name of an S3 attribute as the name of an S4 slot. It's tempting to “promote” an attribute to a slot, but the resulting confusion between slot and attribute is hard to handle.
Frequently, S3Part
can and should be avoided by simply
coercing objects to the desired class; methods are automatically
defined to deal correctly with the slots when as
is
called to extract or replace superclass objects.
The function slotsFromS3()
is a generic function used
internally to access the slots associated with the S3 part of the
object. Methods for this function are created automatically when
setOldClass
is called with the S4Class
argument. Usually, there is only one S3 slot, containing the S3
class, but the S4Class
argument may provide additional slots,
in the case that the S3 class has some guaranteed attributes that
can be used as formal S4 slots. See the corresponding section in
the documentation of setOldClass
.
S3Part
: Returns or sets the S3 information
(and possibly some S4 slots as well, depending on arguments
S3Class
and keepSlots
). See the discussion of
argument strict
above. If it is TRUE
the value
returned is an S3 object.
S3Class
: For an object from a class extending S3
classes, returns or sets the character vector of class(es) stored in
the object. Note that S3Class
on any other object returns
the value of class
.
isXS3Class
: Returns TRUE
or FALSE
according
to whether the class defined by ClassDef
extends S3 classes (specifically, whether it has the slot for
holding the S3 class).
slotsFromS3
: returns a list of the relevant slot classes, or an
empty list for any other object.
Objects in R have an internal bit that indicates whether or not to
treat the object as coming from an S4 class. This bit is tested by
isS4
and can be set on or off by asS4
.
The latter function, however, does no checking or interpretation;
you should only use it if you are very certain every detail has been
handled correctly.
As a friendlier alternative, methods have been defined for coercing
to the virtual classes "S3"
and "S4"
. The expressions
as(object, "S3")
and as(object, "S4")
return S3
and S4 objects, respectively. In addition, they attempt
to do conversions in a valid way, and also check validity when
coercing to S4.
The expression as(object, "S3")
can be used in two ways. For
objects from one of the registered S3 classes, the expression will
ensure that the class attribute is the full multi-string S3 class
implied by class(object)
. If the registered class has known
attribute/slots, these will also be provided.
Another use of as(object, "S3")
is to take an S4 object and
turn it into an S3 object with corresponding attributes. This is
only meaningful with S4 classes that have a data part. If you want
to operate on the object without invoking S4 methods, this
conversion is usually the safest way.
The expression as(object, "S4")
will use the attributes in
the object to create an object from the S4 definition of
class(object)
. This is a general mechanism to create
partially defined version of S4 objects via S3 computations (not
much different from invoking new
with corresponding
arguments, but usable in this form even if the S4 object has an
initialize method with different arguments).
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.)
setOldClass
## two examples extending S3 class "lm", class "xlm" directly and "ylm" indirectly
setClass("xlm", representation(eps = "numeric"), contains = "lm")
setClass("ylm", representation(header = "character"), contains = "xlm")
## lm.D9 is as computed in the example for stats::lm
y1 = new("ylm", lm.D9, header = "test", eps = .1)
xx = new("xlm", lm.D9, eps =.1)
y2 = new("ylm", xx, header = "test")
stopifnot(inherits(y2, "lm"))
stopifnot(identical(y1, y2))
stopifnot(identical(S3Part(y1, strict = TRUE), lm.D9))
## note the these classes can insert an S3 subclass of "lm" as the S3 part:
myData <- data.frame(time = 1:10, y = (1:10)^.5)
myLm <- lm(cbind(y, y^3) ~ time, myData) # S3 class: c("mlm", "lm")
ym1 = new("ylm", myLm, header = "Example", eps = 0.)
##similar classes to "xlm" and "ylm", but extending S3 class c("mlm", "lm")
setClass("xmm", representation(eps = "numeric"), contains = "mlm")
setClass("ymm", representation(header="character"), contains = "xmm")
ym2 <- new("ymm", myLm, header = "Example2", eps = .001)
# but for class "ymm", an S3 part of class "lm" is an error:
try(new("ymm", lm.D9, header = "Example2", eps = .001))
setClass("dataFrameD", representation(date = "Date"), contains = "data.frame")
myDD <- new("dataFrameD", myData, date = Sys.Date())
## S3Part() applied to classes with a data part (.Data slot)
setClass("NumX", contains="numeric", representation(id="character"))
nn = new("NumX", 1:10, id="test")
stopifnot(identical(1:10, S3Part(nn, strict = TRUE)))
m1 = cbind(group, weight)
setClass("MatX", contains = "matrix", representation(date = "Date"))
mx1 = new("MatX", m1, date = Sys.Date())
stopifnot(identical(m1, S3Part(mx1, strict = TRUE)))