setOldClass {methods}R Documentation

Specify Names for Old-Style Classes

Description

Register an old-style (a.k.a. `S3') class as a formally defined class. The Classes argument is the character vector used as the class attribute; in particular, if there is more than one string, old-style class inheritance is mimicked. Registering via setOldClass allows S3 classes to appear in method signatures, and as a slot in an S4 class if a prototype is included.

Usage

setOldClass(Classes, prototype, where, test = FALSE)

Arguments

Classes A character vector, giving the names for old-style classes, as they would appear on the right side of an assignment of the class attribute.
prototype An optional object to use as the prototype. This should be provided as the default S3 object for the class, if you plan to use the class as a slot in an S4 class. See the details section.
where Where to store the class definitions, the global or top-level environment by default. (When either function is called in the source for a package, the class definitions will be included in the package's environment by default.)
test flag, if TRUE, inheritance must be tested explicitly for each object, needed if the S3 class can have a different set of class strings, with the same first string. See the details below.

Details

Each of the names will be defined as an S4 class, extending the remaining classes in Classes, and the class oldClass, which is the “root” of all old-style classes. S3 classes have no formal definition, and therefore no formally defined slots. If a prototype argument is supplied in the call to setOldClass(), objects from the class can be generated. If the S3 class is to be a slot in an S4 class, providing a prototype is recommended. Otherwise, the class will be created as a virtual S4 class; method dispatch will still work and inheritance will follow the S3 class hierarchy, but actions that require a prototype object from the class will not. For example, using the class as a slot in an S4 class definition will set the corresponding slot to NULL in the prototype for the S4 class.

Providing a prototype allows the function new() to be called for this class, but optional arguments in this call are not meaningful, since the class has no formal slots. Extending an S3 class with an S4 class is formally legal, but discouraged. Since the S4 subclass will have a single character string in its class(), S3 inheritance will not work. Also, there is no safe way for a general object from the S3 class to be inserted when an object is generated from the subclass.

See Methods for the details of method dispatch and inheritance. See the section Register or Convert? for comments on the alternative of defining “real” S4 classes rather than using setOldClass.

Some S3 classes cannot be represented as an ordinary combination of S4 classes and superclasses, because objects from the S3 class can have a variable set of strings in the class. 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 once for each superclass.

For example, ordered factors always have the S3 class c("ordered", "factor"). This is proper behavior, and maps simply into two S4 classes, with "ordered" extending "factor".

But objects whose class attribute has "POSIXt" as the first string may have either (or neither) of "POSIXct" or "POSIXlt" as the second string. This behavior can be mapped into S4 classes but now to evaluate is(x, "POSIXlt"), for example, requires checking the S3 class attribute on each object. Supplying the test=TRUE argument to setOldClass causes an explicit test to be included in the class definitions. It's never wrong to have this test, but since it adds significant overhead to methods defined for the inherited classes, you should only supply this argument if it's known that object-specific tests are needed.

The list .OldClassesList contains the old-style classes that are defined by the methods package. Each element of the list is an old-style list, with multiple character 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.

Register or Convert?

A call to setOldClass creates formal classes corresponding to S3 classes, allows these to be used as slots in other classes or in a signature in setMethod, and mimics the S3 inheritance.

Supplying the prototype and optionally the generator arguments allows the S4 class created to be non-virtual, making it a candidate to be a slot in S4 class definitions and to be extended by S4 classes. The class still does not have formally defined slots. Because R implements slots as attributes, an S3 class that uses attributes (factor, for example) can in principle be defined as an S4 class with slots. However, a class such as lm that uses components of a list in a similar role cannot have formal slots. The slots would not be interpreted by S3 code written for lm objects.

If your class does in fact have a consistent set of attributes, so that every object from the class has the same structure, you may prefer to take some extra time to write down a specific definition in a call to setClass to convert the class to a fully functional formal class. On the other hand, if the actual contents of the class vary from one object to another, such a definition will not generally be possible. You should still register the class via setOldClass, unless its class attribute is hopelessly unpredictable.

An S3 class has consistent structure if each object has the same set of attributes, both the names and the classes of the attributes being the same for every object in the class. In practice, you can convert classes that are slightly less well behaved. If a few attributes appear in some but not all objects, you can include these optional attributes as slots that always appear in the objects, if you can supply a default value that is equivalent to the attribute being missing. Sometimes NULL can be that value: A slot (but not an attribute) can have the value NULL. If version, for example, was an optional attribute, the old test is.null(attr(x,"version") for a missing version attribute could turn into is.null(x@version) for the formal class.

The requirement that slots have a fixed class can be satisfied indirectly as well. Slots can be specified with class "ANY", allowing an arbitrary object. However, this eliminates an important benefit of formal class definitions; namely, automatic validation of objects assigned to a slot. If just a few different classes are possible, consider using setClassUnion to define valid objects for a slot.

See Also

setClass, setMethod

Examples


setOldClass(c("mlm", "lm"))
setGeneric("dfResidual", function(model)standardGeneric("dfResidual"))
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)



rm(myData, myLm)
removeGeneric("dfResidual")
## Not run: setOldClass("data.frame", prototoype = data.frame())

## End(Not run)

[Package methods version 2.5.0 Index]