The R Project SVN R

Rev

Rev 88547 | 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-2026 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{difftime-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 defined
  class. Simple usage will be of the form:

\code{setOldClass(Classes)}


where \code{Classes} is the character vector that would be the
  \code{class} attribute of the S3 object. Calls to
  \code{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 \link{Methods_for_S3}).
  Formal classes can also contain a registered S3 class (see
  \link{S3Part} for details).

  If the S3 class has a known set of attributes, an
  equivalent S4 class can be specified by \code{S4Class=} in the call to
  \code{setOldClass()}; see the section  \dQuote{Known Attributes}.
}

\usage{
setOldClass(Classes, prototype, where, test = FALSE, S4Class)
}
\arguments{
  \item{Classes}{
    A character vector, giving the names for S3
    classes, as they would appear on the right side of an assignment of
    the \code{class} attribute in S3 computations.

    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.
  }
  \item{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 \code{Classes} argument.  See the section
    on \dQuote{S3 classes with known attributes} below.
  }
  \item{prototype, where, test}{\emph{These arguments are currently
        allowed, but not recommended in typical applications.}

  \code{prototype}:
    An optional object to use as the prototype.  If the S3 class is
    not to be \code{VIRTUAL} (the default), the use of \code{S4Class=} is
    preferred.

  \code{where}:
    Where to store the class definitions. Should be the default (the
    package namespace) for normal use in an application package.

  \code{test}: flag, if \code{TRUE}, arrange to test inheritance
    explicitly for each object, needed if the S3 class can have a
    different set of class strings, with the same first string.
    Such classes are inherently malformed, are rare, and should be avoided.
  }
}
\details{
  The name (or each of the names) in \code{Classes} will be defined as an S4 class, extending class \code{oldClass},
  which is the \sQuote{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 \code{"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 \code{NULL}.

  See \link{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 \code{setOldClass} with argument
  \code{test=TRUE}.
}

\section{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 \code{.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 \code{setOldClass} when
  creating the \pkg{methods} package; therefore, these classes can be used
  in \code{\link{setMethod}} calls, with the inheritance as implied by
  the list.
}

\section{S3 Classes with known attributes}{
  A further specification of an S3 class can be made \emph{if} the
  class is guaranteed to have some attributes of known class (where as
  with slots, \dQuote{known} means that the attribute is an object of
  a specified class, or a subclass of that class).

  In this case, the call to \code{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 \code{S4Class=} to \code{setOldClass()}.

  See the definition of class \code{"ts"} in the examples below and
  the \code{data.frame} example in Section 10.2 of the reference.
  The call to \code{\link{setClass}} to create the S4 class can use the same
  class name, as here, so long as the call to \code{setOldClass}
  follows in the same package.  For clarity it should be the next
  expression in the same file.

  In the example, we define \code{"ts"} as a vector structure with a
  numeric slot for \code{"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 \code{"ts"} objects will
  behave as vector structures and will have a numeric \code{"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 \code{"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 \linkS4class{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., \code{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., \code{"lm"}).  An attribute
  that is sometimes missing cannot be represented as a slot, not even
  by pretending that it is present with class \code{"NULL"}, because
  attributes, unlike slots, can not have value \code{NULL}.

  One irregularity that is usually tolerated, however, is to optionally
  add other attributes to those guaranteed to exist (for example,
  \code{"terms"} in \code{"data.frame"} objects returned by
  \code{\link{model.frame}}).  Validity checks by
  \code{\link{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.
}

\seealso{
  \code{\link{setClass}}, \code{\link{setMethod}}
}


\references{
  \bibinfo{R:Chambers:2016}{footer}{(Chapters 9 and 10, particularly
    Section 10.8)}
  \bibshow{R:Chambers:2016}
}


\examples{
\dontshow{
## All the predefined S3 classes with S4 versions
sort(unlist(.OldClassesList))
}

require(stats)

## "lm" and "mlm" are predefined; if they were not this would do it:
\dontrun{
setOldClass(c("mlm", "lm"))}

## 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)

\dontshow{
showClass("data.frame")# to see the predefined S4 "oldClass"
}

## 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}.


\dontshow{
stopifnot(identical(dfResidual(myLm), myLm$df.residual))
removeClass("ylm"); removeClass("xlm")
rm(myData, myLm)
removeGeneric("dfResidual")}

\dontrun{
## 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)
}

}
\keyword{ programming }
\keyword{ methods }