Object-Oriented Programming in R: S4 Classes

Now that we’ve seen a quick introduction to object-oriented programming in R, let’s talk about the functions for building classes in more depth.

To create a new class in R, you use the setClass function:

setClass(Class, representation, prototype, contains=character(),
         validity, access, where, version, sealed, package,
         S3methods = FALSE)

Here is a description of the arguments to setClass.

ArgumentDescriptionDefault
ClassA character value specifying the name for the new class. (This is the only required argument.) 
representationA named list of the different slots in the class and the object name associated with each one. (You can specify “ANY” if you want to allow arbitrary objects to be stored in the slot.) 
prototypeAn object containing the default object for slots in the class. 
containsA character vector containing the names of the classes that this class extends (usually called superclasses).character()
validityA function that checks the validity of an object of this class. (Default is no validity check.) May be changed later with setValidity. 
accessNot used; included for compatibility with S-PLUS. 
whereThe environment in which to store the object definition.Default is the environment in which setClass was called.
versionNot used; included for compatibility with S-PLUS. 
sealedA logical value to indicate if this class can be redefined by calling setClass again with the same class name. 
packageA character value specifying the package name for this class.Default is the name of the package in which setClass was called.
S3methodsA logical value specifying whether S3 methods may be written for this class.FALSE

To simplify the creation of new classes, the methods package includes two functions for creating the representation and prototype arguments, called representation and prototype. These functions are very helpful when defining classes that extend other classes as a data part, have multiple superclasses, or combine extending a class and slots.

Some slot names are prohibited in R because they are reserved for attributes. (By the way, objects can have both slots and attributes.) Forbidden names include "class", "comment", "dim", "dimnames", "names", "row.names" and "tsp".

If a class extends one of the basic R types (as described in Table 10-1), there will be a slot called .Data containing the data from the basic object type. R code that works on the built-in class will work with objects of the new class; they will just act on the .Data part of the object.

You can explicitly define an inheritance relationship with the setIs function. (This is an alternative to using the contains argument for setClass.)

setIs(class1, class2, test=NULL, coerce=NULL, replace=NULL,
      by = character(), where = topenv(parent.frame()), classDef =,
      extensionObject = NULL, doComplete = TRUE)

To explicitly set a validation function for a class, you use the setValidity function:

setValidity(Class, method, where = topenv(parent.frame()) )

Whenever you create a new object, R will execute the initialize method of the class (if the method is available). Programmers usually use the initialize method to calculate values or create additional objects and assign them to slots. See Methods for information on how to add a method for the generic function initialize.

R also allows you to define a virtual class that is a superclass of several other classes. This can be useful if the virtual class does not contain any data by itself but you want to create a set of methods that can be used by a set of other classes. To do this, you would use the setClassUnion function:

setClassUnion(name, members, where)

This function takes the following arguments.

ArgumentDescription
nameA character value specifying the name of the new superclass
membersA character vector specifying the names of the subclasses
whereThe environment in which to create the new superclass

You can create a new object in R through a call to the class’s new method. (In object-oriented programming lingo, this is called a constructor.) Calling:

new(c,...)

returns a new object of class c. It is possible to fill data into the slots of the new object by specifying named arguments in the call to new; each slot will be set to the value specified by the corresponding named argument. If a method named initialize exists for class c, then the function initialize will be called after the new object is created (and the slots are filled in with the optional arguments).

You can fetch the value stored in slot slot_name of object object_name through a call to the function slot(slot_name, object_name). R includes a special operator for accessing the objects stored inside another object that is a shorthand for the slot function: the @ operator. This operator takes the form object_name@slot_name.

It is also possible to set the object stored in a slot with the familiar assignment operator. For example, to set the “month” slot of a “birthdate” object to the value “June,” you would call:

> birthdate@month <- "June"

or, alternatively:

> slot(birthdate, month) <- "June"

By default, when changing a value in an object, R will check the validity of the new object. However, it is possible to override this check by using the check=FALSE option when calling slot:

> slot(birthdate, month, check=FALSE) <- "June"

Doing so is usually unwise and unnecessary.

To test whether an object o is a member of a class c, you can use the function is(o, c). To test whether a class c1 extends a second class c2, you can use the function extends(c1, c2).

To get a list of the slots associated with an object o, you can use the function slotNames(o). To get the classes associated with those slots, use getSlots(o). To determine the names of the slots in a class c, you can use the function slotNames(c). Somewhat nonintuitively, getSlots(c) returns the set of classes associated with each slot.

It is possible to convert an object o to class c by calling as(o, c).

To enable coercion for a class that you define, make sure to register coercion methods with the setAs function:

setAs(from, to, def, replace, where = topenv(parent.frame()))

This function takes the following arguments.

ArgumentDescriptionDefault
fromA character value specifying the class name of the input object. 
toA character value specifying the class name of the output object. 
defA function that takes an argument of type from and returns a value of type to. In other words, a function that performs the conversion. 
replaceA second function that may be used in a replacement method (that is, the method to use if the as function is used as the destination in an assignment statement). This is a function of two arguments: from and value. 
whereThe environment in which to store the definition.topenv(parent.frame())

In Chapter 9, we showed how to use functions in R. An important part of a function definition in R is the set of arguments for a function. As you may recall, a function accepts only one set of arguments. When you assign a function directly to a symbol, you can only call that function with a single set of arguments.

Generic functions are a system for allowing the same name to be used for many different functions, with many different sets of arguments, from many different classes.

Suppose that you define a class called meat and a class called dairy and a method called serve. In R, you could assign one function to serve a meat object and another function to serve a dairy object. You could even assign a third function that took both a meat object and a dairy object as arguments and allowed you to serve both of them together. This would not be kosher in some other languages, but it’s OK in R.[30]

The first step in assigning methods is to create an appropriate generic function (if the function doesn’t already exist). To do this, you use the setGeneric function to create a generic method:

setGeneric(name, def= , group=list(), valueClass=character(),
           where= , package= , signature= , useAsDefault= ,
           genericFunction= , simpleInheritanceOnly = )

This function takes the following arguments.

ArgumentDescription
nameA character value specifying the name of the generic function.
defAn optional function defining the generic function.
groupAn optional character value specifying the group generic to which this function belongs. See the help file for S4groupGeneric for more information.
valueClassAn optional character value specifying the name of the class (or classes) to which objects returned by this function must belong.
whereThe environment in which to store the new generic function.
packageA character value specifying the package name with which the generic function is associated.
signatureAn optional character vector specifying the names of the formal arguments (as labels) and classes for the arguments to the function (as values). The class name “ANY” can be used to mean that arguments of any type are allowed.
useAsDefaultA logical value or function specifying the function to use as the default method. See the help file for more information.
genericFunctionNot currently used.
simpleInheritanceOnlyA logical value specifying whether to require that methods be inherited through simple inheritance only.

To associate a method with a class (or, more specifically, a signature with a generic function), you use the setMethod function:

setMethod(f, signature=character(), definition,
          where = topenv(parent.frame()),
          valueClass = NULL, sealed = FALSE)

Here is a description of the arguments for setMethod.

ArgumentDescriptionDefault
fA generic function or the name of a generic function. 
signatureA vector containing the names of the formal arguments (as labels) and classes for the arguments to the function (as values). The class name “ANY” can be used to mean that arguments of any type are allowed.character()
definitionThe function to be called when the method is evaluated. 
whereThe environment in which the method was defined.topenv(parent.frame())
valueClassNot used; included for backward compatibility.NULL
sealedUsed to indicate if this class can be redefined by calling setClass again with the same class name.FALSE

The methods package includes a number of functions for managing generic methods.

The methods package also includes functions for managing methods.

For more information on these functions, see the corresponding help files.

Classes for built-in types are shown in Table 10-1; these are often called basic classes. All classes are built on top of these classes. Additionally, it is possible to write new methods for these classes that override the defaults.

The vector classes (integer, numeric, complex, character, logical, and raw) all extend the vector class. The vector class is a virtual class.

Many tools for working with classes are included in the methods package, so you can find additional help on classes with the command library(help="methods").



[30] In technical terms, R’s implementation is called parametric polymorphism.