Help @ MC
The [R] environment
Help @ MC Logo
Centre for Mathematical Sciences, Lund University
    Print this page!
Home

Up to Help

Docs
R Help

Packages
CRAN
R.oo
aroma

Install
The R software
Most packages

Tips'n'Tricks
install.packages
Rgui (Windows)

External Links
R homepage
Download R
bioconductor.org
braju.com packages



Printer-friendly
Print this page



Powered by Google

Going from S3 to S4 object oriented programming in [R]

January 2002, Henrik Bengtsson

Please note that these notes was written in early 2002 when I was not that familiar with the methods package, which also has evolved quite a bit since then. Therefore, some of the comments below might be incorrect or invalid.

Introduction

Starting with [R] v1.4.0 a new class formalism referred to as S4 classes/objects is introduced which is implemented in the package methods by John Chambers [1,2].

Methods in S3

Assume that we have an object refered to as sq of class Square, which is a subclass of Rectangle which in turn is a subclass of Shape. Pre [R] v1.4.0 the only generic function mechanism which can be used for an object-oriented style of programming available was using a method despatch based one S3 and the UseMethod function. Using S3 we define a getArea method for class Rectangle as

  getArea.Rectangle <- function(object) {
    attr(object, "sideA") * attr(object, "sideB");
  }

given that a Rectangle object has the two attributes sideA and sideB (starting with [R] v1.4.0 these arguments can be accessed directly using the @ operator, i.e. object@sideA and object@sideB, respectively). Then we define a generic function getArea:

  getArea <- function(object, ...) UseMethod("getArea");

When this function is called by getArea(sq), UseMethod will method despatch the call based on the class of the first argument, i.e. object. Since sq is of class Square, it will first try to call a method named getArea.Square. If no such method exists, getArea.Rectangle will be tried and so on. If there where no methods defined for any of the classes which object is an instance of, then getArea.default will be tried.

Methods in S4

Below examples will show how you can move from using S3 style of calling class methods to the S4 style.

Define a generic function

In some situations the generic function are generated automatically, but if you would like to define a generic function explicitly it can be done by

  setGeneric("getArea", function(object, ...) standardGeneric("getArea"));

Note how standardGeneric corresponds to UseMethod in S3 style. One difference is that is alright to have code before standardGeneric whereas this is not possible in UseMethod. To be clear here, it is not possible to substitute standardGeneric with UseMethod and vice versa.

Define a method specific to a class

A method for a specific class is defined using the setMethod. For instance, a getArea method for the class Rectangle can be defined by

  getArea.Rectangle <- function(object, ...) {
    object@sideA * object@sideB;
  }

  setMethod("getArea", "Rectangle", getArea.Rectangle);

Alternatively it is possible to directly define it as

  setMethod("getArea", "Rectangle", function(object, ...) {
    stop(paste("Method getArea() is not defined for this class:",
               data.class(object)));
  })

It is important to know that the methods must have exactly the same arguments as the generic function. Since we defined the generic function to have the arguments object and ... the getArea methods of all classes must have these two arguments and only these two arguments.

Define a default method

Postponing the explanation, a default method can be defined, using S4 style, as

  setMethod("getArea", "ANY", function(object, ...) {
    stop(paste("Method getArea() is not defined for this class:",
               data.class(object)));
  })

The signature "ANY" corresponds to the ".default" suffix of the name of the default method in S3 style. Note that setGeneric must be called first, otherwise the following error will be given:

  Error in setMethod("getArea", "ANY", function(object, ...) { :
          No existing definition for function "getArea"

Define a no-argument function with the same name as a generic function

Here the signature "missing" comes in handy:

  getArea.missing <- function() {
    cat("Method getArea() was called without arguments.\n");
  }

  setMethod("getArea", "missing", function(object, ...) getArea.missing());

You might wonder why we do not define the method as setMethod("getArea", signature("missing", "missing"), getArea.missing()). This would be correct, but due to a bug in the current version of the package methods this does not work, but it will probably work in a future realease [3].

Define a method with name that is already taken

It sometimes happens that one needs to define a method of a class, but there is already a function with the same name and it does not match your arguments. Take for instance the case where one wants to define the method licence for the class Software. Since there already exists a function called licence() in the [R] base package we can not just use setMethod. First we have to define a generic function and make sure that the original function is called when no arguments are passed;

  if (!exists("licence.missing")) licence.missing <- licence;
  setGeneric("licence", function(object, ...) standardGeneric("licence"));
  setMethod("licence", "missing", function(object, ...) licence.missing());

Note how the if statement asserts that the assignment of licence.missing is only done once. The three lines above will "convert" an function definition that is non-generic into a generic function with a default method. Second, we define the method for the Software class:

  setMethod("licence", "Software", function(object, ...) {
    # Some code here.
  });

References

[1] John M. Chambers, Programming with Data - A Guide to the S Language, Springer-Verlag, 1998.
This book is also known as the Green Book.
http://cm.bell-labs.com/cm/ms/departments/sia/Sbook/
[2] John M. Chambers, The Definition of Generic Functions and Methods, 2002.
http://developer.r-project.org/methodDefinition.html
[3] John M. Chambers, Personal communication, Jan 2002.
[4] John M. Chambers, Classes and Methods in the S Language, Bell Laboratories, Lucent Technologies August 9, 2001.
http://www.omegahat.org/RSMethods/Intro.ps, http://www.omegahat.org/RSMethods/Intro.pdf
[5] T. Lumley, Objects and methods, R Development Core Group.
http://faculty.washington.edu/tlumley/Rcourse/objects.pdf