The R.oo package

Object-oriented programming with references using S3/UseMethod

Version 0.3, November 2002

Henrik Bengtsson
Mathematical Statistics, Centre for Mathematical Sciences
Lund University, Sweden

This document is a pre-print of the peer-reviewed proceeding, which is recommended instead:

Table of Content

1. Introduction

The core functionality of R does provide a paradigm for programming with objects and classes. The paradigm is often referred to as S3 or S3/UseMethod, the latter because the S3 functionality relies heavily on the UseMethod() function. Quite recently another method of programming with classes was made available. It is referred to as the S4 paradigm and relies on a package named methods [1], which comes with the standard R distribution. This document and the package described here will only use the S3 paradigm.

For beginners, but also for experts, it is quite tedious to safely implement an object-oriented design using the standard S3 (or S4) paradigm. It is easy to forget to add a generic function or even worse, to overwrite a non-generic function by a generic function. As a developer and programmer one has to stay up to date with all generic functions and all functions implemented in the latest R distribution to be sure that core functionalities in R are not not overridden or removed when ones package is loaded. To be certain that the package will work anywhere one must also stay up to date with all other packages that the end-user might load in parallel with your package. This is not a tractable solution.

In R arguments are supplied to functions by the pass-by-value semantic, also known as call-by-value. Inside the function the arguments behave like local variables and any change made to a value inside the function is not reflected in the original value. The rational for this is that a function should take one or several input values and optionally return something else and it should never modify the input values. When passing large data objects to a function true pass-by-value approach would be very expensive in terms of time and memory. For this reason an argument is passed by reference as long as the value is never change by the function (this is possible since R is running as a single thread). As soon as the function is making a change to the value, a local copy of the argument is created to obtain pass by value. Occasionally there are requests for adding a true pass-by-reference semantic such that functions can modify the original value. From now on we will refer to a function that (might) modify a variable as a method and reserve the word function for its original meaning. There are ways to emulate a pass-by-reference semantic by letting regular R variables represent reference variables or shortly references. With references it is possible to write more memory and time efficient code. Another major advantage is that it is possible to write more user-friendly methods where less argument needs to be specified by the end-user.

For reasons like these the R.oo package was developed. Its purpose is to relieve the developer from such details to make it possible to focus on the object-oriented design. The utility functions setConstructorS3() and setMethodS3() will create constructor functions and class methods and at the same time make sure that required generic functions are created (or not) and warn the programmer if illegal method names are used etc. The package provides a totally transparent way of using references by defining a new "data type", namely the class Object. Any data object that is supposed to be passed by reference should inherit from this so called root class. In addition, using one root class that all classes inherit from will improve the overall design of any developed package. Finally, the R.oo package also provides a more powerful exception handling mechanism where an exception can be thrown and then caught depending on its class. The R.oo package is written using standard R code ("100% R") and is itself designed and implemented in an object-oriented way.

This document will not discuss what object-oriented programming and design are about. For an extensive case study example of how to use the R.oo package see [2]. In section 2 we start by describing how S3 classes are commonly used, not only in the context of the R.oo package. This section will also describe some additional features that come with the Object class. In section 3 a R coding convention (RCC) is suggested. The utility functions for defining constructors and methods introduced in section 4 will by default assert that the RCC is followed. The root class named Object will be described in detail in section 5 and the usage of references, which is provided by the Object class, will be discussed in section 6. Section 7 is about exception handling and section 8 explains some other utility functions that is part of the package. Conclusions are given in section 9. Section 10 explains how the package is downloaded and installed and section 11 explains the license. Section 12 explains how to cite this document.

2. Using classes

Throughout this document we will make use of a very simple but explanatory example to describe the major parts of the package. Let the class SavingsAccount represent a bank account, which in the simplest case can be described by its balance. To secure against illegal modifications of the balance we represent the balance with a private field named .balance. It is good custom to let names of private variables in R to have a period as a prefix. See section 3 for more details. To obtain the balance of the account the function getBalance() is provided. Using setBalance() it is possible to modify the account balance directly, but it is not possible to set it to a negative balance. More commonly used are the methods for withdrawal and depositing, i.e. withdraw(amount) and deposit(amount), respectively. The withdrawal method will not accept withdrawals if the balance goes below zero. The class will also inherit from the root class Object, which will be explained in much more details below. When a new bank account is opened, i.e. when a new SavingsAccount object is created, the balance is by default set to zero. A Unified Modeling Language (UML) model of the SavingsAccount class is depicted in the figure below.

.balance: double
getBalance(): double

Figure: UML representation of the SavingsAccount class.

2.1 Creating an object

The implementation of the class will be described in section 4, but for now assume that the usage of the constructor is SavingsAccount(balance=0) and that

account <- SavingsAccount(100)

will create a SavingsAccount object with initial balance 100. The object is referred to by the reference variable account.

2.2 Accessing fields

The fields of a instance of class inheriting from root class Object, shortly an Object, can be accessed similar to how elements of a list are accessed. For example, the balance field of the account object can the be retrieved by either account$.balance or account[[".balance"]]. To set the balance of the account either account$.balance <- newBalance or account[[".balance"]] <- newBalance will do.

Note that there are no ways to prevent the access to private fields. However, if one follows the RCC rule that private fields and only private fields should have a . (period) prefix, it should be clear which fields should be accessed from outside and which should only be accessed from inside methods of the SavingsAccount class. Also, private fields, i.e. with a period prefix, will by default not be listed by getFields() and ll() (see below). This is the reason why we decided to name the balance field .balance.

2.3 Calling methods of a class

Under the S3 paradigm, a method of a class is called in the same way as a regular function, but with the reference to the object as the first argument. When specifying the withdrawal and depositing methods above, we excluded this object argument for simplicity, which follows the UML standard, e.g. withdraw(amount). However, when calling the method one has to include it, e.g. withdraw(account, amount). All classes derived from Object also provide a second way of calling methods. Like fields, methods can be accessed via the $ (or the [[) operator, e.g. account$withdraw(amount). In many other object-oriented languages such as Java and C++, and also the Omegahat's OOP project [3], this is the format how methods are called. This latter format also motivates why we excluded the first argument when we specified the methods in the first place.

2.4 Calling class methods

A class method, also known as a static method of a class, is invoked using only the class name and it does not require an instantiated object. The most readable way to call a class method is via the $ operator, e.g. Object$load(file) and Exception$getLastException(), even though it is also possible to call it the classical way where the first argument is any instance of the class, e.g. load(Object(), file) and getLastException(Exception()).

2.5 Accessing virtual fields

Finally, there is a third way of calling methods of a class. A Method with a name of format get<Field>(object) or set<Field>(object, value), e.g. getBalance(account) and setBalance(account, newBalance), can be accessed by via a so called virtual field of name <field>, e.g. account$balance and account$balance <- value. By default, virtual fields have higher priority than regular fields, meaning that if virtual field exists that will be accessed first. It is possible on a reference-to-reference or object-to-object basis to change the order which fields, virtual fields, methods and static methods are accessed.

There are at least three real advantages of using virtual fields. First, it is possible, as the name implies, to make it look like a class has a field of a certain name, whereas it internally is using something else. For instance, a Circle class can have the two redundant fields named radius and diameter of which one is a virtual field and the other is an actual field, which one is one does really not matter. In practice, both might be virtual. We see that using virtual fields can reduce the redundancy, which in turn minimizes the risk for inconsistency. It can also reduce the memory usage. Another real advantage is that it is possible restrict what values can be assigned to a field. For instance, the setRadius(newRadius) method can prevent the user (the programmer) from setting a negative radius, e.g. circle$radius <- -20, by throwing an exception. For more information about exceptions see section 7 below. Using virtual fields it is possible to encapsulate a private or prevent the modification of it, which in turn provides a method of emulating constants.

2.6 Accessing class fields

A class field, also known as static fields, is a field associated with a class as a whole, not with a particular instance of the class. A class field of class is also shared by all objects of that class. A common role of a class field is that of a global variable (except from the important different that it is not a global variable), e.g. Colors$RED.HUE. A class field is accessed as a regular field except that the object is now the static class object, e.g. SavingsAccount$count <- SavingsAccount$count + 1.

3. Coding conventions

An important part of object-oriented design and implementation is to follow a standard for describing the design and for implementing it. There are several standards for describing object-oriented design of software, but one that has become the major standard is the Unified Modelling Language, also referred to as UML [4]. For implementation standards, sometimes referred to as coding conventions, some languages has a well defined specification to follow whereas others have not. Unfortunately, R is not one of them. A well defined coding convention is useful because it helps to make the code more readable and reduce the risk for mistakenly reassigning constants etc. It is also fundamental for sharing source code between developers and over time. For this reason we are working on a R Coding Conventions (RCC) draft [5]. Next we will give a small excerpt of the RCC.

3.1 Naming conventions

Some of the naming convention rules of the RCC apply to object-oriented design and programming. One of the most important is how classes, fields and methods should be named. According to RCC, names representing classes must be nouns and written in mixed case starting with upper case, e.g. SavingsAccount. Both field and method names must be in mixed case starting with lower case, e.g. balance and getBalance(). Private fields should have a . (period) as prefix, e.g. .balance, to make it clear that it is a private field. Private fields are by default not listed by utility methods like getFields(), ls() and ll(). The methods setConstructorS3() and setMethodS3(), which will be described in detail in the next section, will enforce the programmer to follow some of the naming rules of the RCC specification. Not all rules are enforced, because the developed program also has to be compatible with the basic R functions too, which (for obvious reasons) do not comply with our RCC draft. As a last resort, it is always possible to turn of the test against RCC by using the argument enforceRCC=FALSE when using the above to functions.

4. Defining new classes

Under the S3 schema there is no way to formally define a class. There is no way to enforce that an instance of a class has the correct format, contains the correct fields, or to assure that the inheritance structure is valid. The S4 schema is trying to over-come some of these lack-of-robustness drawbacks. The way the Object class is designed, the idea is that the fields (and hence the class) are defined inside the constructor function. In this section we will introduce the two utility functions setConstructorS3() and setMethodS3(), which will help the programmer creating constructors and class methods without having to worry about generic functions. Note that these two functions can be used independently of the class Object.

4.1 Defining constructors

The setConstructorS3() will set the constructor function, which also defines the fields of the class. For example, to create the SavingsAccount class do:

setConstructorS3("SavingsAccount", function(balance=0) {
  if (!is.numeric(balance) && length(balance) != 1)
    throw("Argument 'balance' must be a single numeric value: ", mode(balance));
  if (balance < 0)
    throw("Trying to create an account with a negative balance.");

  extend(Object(), "SavingsAccount", 
    .balance = balance

The method throw() works similar to stop() and will be explained more in section 7. The definition of the inheritance is done through the extend() method of the Object class. Recall that all classes should be derived from the root class Object. The first argument to extend() is the resulting object from calling the constructor of the wanted superclass. In the example above, the SavingsAccount inherits directly from the Object class, which is done by calling its constructor. The second argument to extend() should be the name of the class to be defined, e.g. SavingsAccount. According to the RCC rules, the name of the class should be the same as the name of the constructor function. Any other arguments to extend() are optional, but they must be named value arguments, e.g. .balance=balance. The names of such arguments will declare the fields of the class and their values will be used when the object is created. Note that according to the RCC fields starting with a . (period) are supposed to be private fields. Finally, all classes derived from Object must comply to the rule that it is must be possible to create an instance of it by calling its constructor with no argument, e.g. account <- SavingsAccount(). The reason for this is that static class objects are created by calling the constructor with no arguments.

4.2 Defining methods

The setMethodS3() method creates methods for S3 classes and at the same time encapsulates a lot of tedious details that the programmer should not have to think about. One such thing is if a generic function should be created or not and if so, how it should be created. For a detailed discussion on how to create generic functions see [6]. To create the setBalance(newBalance) method for the SavingsAccount class, the only thing that is needed is:

setMethodS3("setBalance", "SavingsAccount", function(this, newBalance) {
  if (newBalance < 0)
    throw("Trying to set balance to an amount less than zero.");
  this$.balance <- newBalance;

The usage of setMethodS3() is:

setMethodS3(name, class="default", definition, private=FALSE, protected=FALSE,
            static=FALSE, abstract=FALSE, trial=FALSE, deprecated=FALSE,
               envir=parent.frame(), createGeneric=TRUE, enforceRCC=TRUE)

where name is the name method, class is the name of the class and definition is the definition, i.e. the function, itself. If class == "default" (or "ANY"), a default method is defined. For information about the other arguments see the help page of the package.

The following section will give some more details on what is going on under the hood.

4.3 Details

The setMethodS3() method will create a standard S3 methods and at the same time it will make sure that a generic function for that method is available. For instance, the evaluation of

setMethodS3("getBalance", "SavingsAccount", function(this) {

will create the S3 method for the class and the S3 generic function, i.e.

getBalance.SavingsAccount <- function(this) {

getBalance <- function(...) UseMethod("getBalance")

It will also make sure that if there already would be a non-generic function called getBalance(), that it would be renamed to getBalance.default(). Methods with suffix .default are called if there exists no methods defined for the classes of the first argument. If such a method also exists there is no way setMethodS3() can solve the problem and therefore an Exception will be thrown saying this. Furthermore, a generic function is only created if there is no generic function or internal function that functions as a generic function. For instance

setMethodS3("as.character", "SavingsAccount", function(this) {
  paste(getClass(this), ": balance is ", this$.balance, ".", sep="");

will only create the S3 method for the class and not the generic function since it already exists. In addition to this, setMethodS3() will by default assert that the (most important) RCC naming rules are followed. If not, it will throw an RccViolationException, which inherit from Exception, with information about what rule was violated. For more information about Exception, see the section about exception handling below.

5. The root class Object

Still to be discussed is the rational and functionality of the so called root class named Object. First of all, by enforcing that all classes should be derived (directly or indirectly) from Object, we automatically know that there exists a set of methods that all classes have in common. This idea already exists in R, but in a pure object-oriented design like this one it is more explicit. For instance, whatever type of object we have, as long as it inherits from Object, we know that we can call the method as.character() and print() on that object and get a valid result. In addition to these two methods there are several other methods that are implemented by the Object class and therefore also are supported by all its subclasses. These methods will be discussed below and can also be seen in the UML representation of Object in the figure below. As explained in section 6, the functionality for references is hidden inside the Object class. Hence we automatically have that all subclasses will support references and that the programmer never has to think about how references should be implemented. They are always provided and always in the same way.


$<-(name, value)
[[<-(name, value)
attach(private=FALSE, pos=2)
extend(this, className, ...)
static load(file)
save(file=NULL, ...)

Figure: UML representation of the root class Object, which all classes should be derived from directly or indirectly through other classes.

The method as.character() returns a string with short information about the Object. This is the same string that by default is displayed by print().

The print() methods prints information about the Object. By default the string returned by as.character() is printed. For any object of any data type or class whose name is typed at the command line followed by an ENTER, the print() of that object will be called. Example:

> 1+2      # gives the object '3', which is then printed, i.e. print(3)
[1] 3
> account  # same as print(account)
SavingsAccount: balance is 100.

The method getFields(private=FALSE) returns the name of all fields in the Object. By default only names of the non-private fields are returned.

The method ll(...) returns a data frame with detailed information about the fields of the Object. By default only non-private fields are listed. For more information see the default function ll() below.

The getClass() method returns a string containing the class name of the Object. Note the difference from class(), which returns the names of all classes the object inherits from.

The hashCode() method returns an integer hash code for the Object.

The objectSize() method returns the (approximate) size (in the number of bytes) of the Object.

The equals(other) method compares the Object with another Object. If they are equal the method should return TRUE, otherwise FALSE. If argument other is NULL, then FALSE should always be returned. The default implementation of equals() is comparing the hashCode() values of both Object.

The clone() method creates an identical copy of the Object. Note that doing ref2 <- ref, will only create a new reference to the same Object.

The methods attach(private=FALSE, pos=2) and detach() attaches and detaches an Object to the search path. By default only public fields (private=FALSE) of an Object are attached and by default they are attached to the beginning of the search path (pos=2) just after the global environment. Note that any modification to such attached fields will not be reflected in the actual Object and when detaching the Object all changes will be lost. The attach-detach mechanism should be used solely for read-only purposes.

The method save(file=NULL, ...) saves an Object to file or to a connection and the static method load(file) will load a previously saved Object and return a reference to it.

Finally, the somewhat special method extend(className, ...) extends an Object into a subclass named according to the string className and contain all fields as given by the ... arguments.

6. References

All instances of the Object class or one of its subclasses are accessed via references. Shortly, for those who are not familiar with references but with pointers, references can be though of as safe pointers to objects that can not by mistake be made to point to the wrong part of the memory. Object-oriented programming using references will not differ much from object-oriented programming using instances, which is the standard way R deals with object. However, there are differences that are important to be aware of. With non-references support, like in standard R, each instance of a class is accessed by one single variable, the object itself. With references, however, it is possible for several variables to access the same object. Here is an example where a list contains several references to the same Object:

person <- Person("Dalai Lama", 68)
l <- list(a=person, b=person)
setAge(l$a, 67)
[1] "Dalai Lama is 67 years old."

If person would not be a reference, the two elements of the list would be another two copies (clones) of the Person object and a modification of one of them would of course not affect the other instance and neither the variable person. Even if such functionality is hardly wanted or needed, it is of course possible to get it with references to:

person <- Person("Dalai Lama", 68)
l <- list(a=clone(person), b=clone(person))
setAge(l$a, 67)
[1] "Dalai Lama is 68 years old."

Furthermore, references make it possible to implement software that would not otherwise be possible or would be very tedious to implement. Using references it is also possible to encapsulate even more details from the end user and thereby make a package even more user-friendly. For a complete example using the R.oo package and references see [2] and [7].

6.1 Garbage collector

As soon as one starts to use pointers or references in a language one normally has to start thinking about what objects are used and what objects can be thrown away to make sure one does not run out of memory. Many languages, such as Java, provide garbage collectors, which automatically clean up the memory. An object that has no references referring to it can, by definition, never be referred to again since there are no references to it anymore. It sits there in memory by itself. A garbage collection is a tool that keeps track of all references and objects and can therefore identify lost objects and de-allocate them from the memory. Luckily, R has such a garbage collector built in. In R you can force the garbage collector to run by gc(), but it will be called automatically whenever the amount of free memory goes below a certain level. Since the R.oo package is making use of environments, the R garbage collector will also work on any object created by methods of the package. For example, an Object created inside a function and for which no references are returned, will automatically be deleted by the R garbage collector. In other words, the programmer does not have to think about deleting objects. The only thing to think of is to make sure to remove the references or to set them to NULL as soon as they are not needed.

6.2 Details

R does not support references. However, references can emulated using so called environments [8], but using environments explicitly will quickly fill the source code with a lot of get(name, envir=ref), assign(name, value, envir=ref) and/or eval(..., envir=ref) statements. This will make the code hard to read and increase the risk for bugs. There are also other ways for emulating references and some are more and some are less memory and time efficient than others. The R.oo package is using the first approach where each object lives in its own environment, but by encapsulating all calls to get() and assign() in the operator methods $(), [[(), $<-() and [[<-() of the root class Object, the developer and programmer will never have to worry about the details.

7. Exception handling

In addition to methods for defining classes and support for references, the package also provides the fundamental functionality for exception handling. The core functionalities for exception handling is done by the Exception class. It provides methods for creating and throwing exceptions and together with its companion method trycatch() complete exception handling is provided.

7.1 Creating and throwing exceptions

The absolute easiest way of creating and throwing an exception is by calling throw(msg) with error message, e.g.

throw("Division by zero.")

which is equivalent to calling

throw(Exception("Division by zero."))

An object of any class that inherits from Exception contains information about when it was created and the message that was added to it when the object was instantiated. Any Exception object can be thrown using the throw() method and then optionally be caught by either the trycatch() or the try() function. If an Exception is thrown, the last exception thrown can be obtained by the static method getLastException() of class Exception.


static getLastException(): Exception
getMessage(): string
getWhen(): POSIX time

Figure: UML representation of the Exception class, which extends the Object class.

The as.character() method of the Object class is overridden by the Exception class and the default print message of an Exception will be like:

> throw("Division by zero.")
Error: [2002-10-20 10:24:07] Exception: Division by zero.

Any kind of exception can be caught by try() as usual:

> try(throw("Division by zero.")); print("It's ok!");
Error: [2002-10-20 10:24:07] Exception: Division by zero.
[1] "It's ok!"

Note that try() defined by the base package, will always print the error message even if the exception is caught. The trycatch() method described next will not do so. It also provides a more delicate way of doing exception handling.

7.2 Catching exceptions depending on class

The trycatch() method can catch any exception thrown based on what class it belongs to. As an example, the following code will generate and throw an exception. The trycatch() method will catch any class of exceptions (ANY), including the try-error class thrown by the stop() function, and safely return.

  x <- log(2);
  y <- log("a");
}, ANY={
  x <- 0;
  y <- 0;

print("trycatch() did indeed catch the exception.");

Like the try() function, the first argument to trycatch() is the code (an expression) to be evaluated and that might throw an exception, e.g. { x <- log(2); y <- log("a"); }. Any other arguments must be named arguments, e.g. ANY={ x <- 0; y <- 0; print(Exception$getLastException()); }, where the name of the argument specify the name of the exception class to be caught. If an exception of that class is thrown the corresponding code will be evaluated. An argument with name ANY will catch any kind of arguments.

Code passed to an argument named finally is guaranteed to always be evaluated immediately before trycatch() returns. This is for instance useful if a connection needs to be closed regardless of a exception is thrown or not.

Not mention yet, the default try() and stop() functions, which are defined by the R base package, are slightly modified by the R.oo package in such a way that they will also support true exception handling.

It is of course possible to create new subclasses of the Exception class, which for instance can contain more detailed information about a specific type of exception.

8. Utility functions

In addition to the classes and methods described above, this package also defines a few other methods that works on any object, i.e. so called default functions or methods for class ANY:

dimension() returns the dimension of an object as a vector of integers. If the base function dim() returns a non-NULL value, that value is returned, otherwise the value from length() is returned. The primary purpose of this function is that it used by ll(). Example:

> dimension(rnorm(1e4))
[1] 10000
> dimension(matrix(nrow=10,ncol=50))
[1] 10 50

charToInt() converts a vector of characters into the corresponding ASCII integers and intToChar() is its inverse function. Example:

> ascii <- charToInt(unlist(strsplit("Hello!\n", "")))
> ascii
[1]  72 101 108 108 111  33  10
> intToChar(ascii)
[1] "H"  "e"  "l"  "l"  "o"  "!"  "\n"

It is primarily used by the default method of hashCode().

The default method of hashCode(), i.e. the method called for object of classes not derived from the Object class, generates hash codes (integers) for non-Object instances. It will for instance create a unique hash code for each unique character string, by converting the string to its ASCII values and combining those into one unique integer. Example:

> hashCode("Hello!\n")
[1] -1824602053

The default method of ll() will list detailed information about the objects (variables and functions) found in an environment. The returned data frame will by default contain information about the member (name of the variable or function), data.class, dimension and object.size, which basically are the value returned by the functions with the same.

As already mentioned, the default method of throw(), will create an Exception with the same message and throw it. In other words, throw(msg) is equal to throw(Exception(msg)). The reason for having a default method of throw() is to let the programmer throw exception easily without having to create an Exception object explicitly each time. Example:

if (denominator == 0)
  throw("Division by zero.");

9. Conclusions

The R.oo package was designed in an object-oriented style and implementated using pure R code (100% R), which is richly commented. It was designed and implemented such that a future transition from S3 to S4 will be as smooth as possible for the developer and the end user. For almost two years, the package has been succesfully used in practice and thoroughly tested, mainly as the object-oriented core of a statistical microarray analysis package named com.braju.sma, [7]. For this reason, we now believe it is mature enough to be officially released.

10. Installation

See http://www.braju.com/R/ for further details.

11. License

It is still to be decided if the R.oo package and the R.classes bundle should be published under either the GPL or the LGPL license. It will be the one that will be most useful for everyone.

12. Related reading

In addition to this talk, there are also two PowerPoint presentations available discussing the R.oo package. The first talk [9] was given at Walter & Eliza Hall Institute of Medical Research on October 2002 and some of the slides might be a little bit out of date. The second talk [10] was given at the Distributed Statistical Computing (DSC 2003) conference in Wienna in March 2003 and is much more up to date.

13. Citing this document

Whenever using the R.oo package please cite according to:

  author       = "Henrik Bengtsson",
  title        = "The {R.oo} package - Object-Oriented Programming with
                  References Using Standard {R} Code",
  booktitle    = "Proceedings of the 3rd International Workshop on 
                  Distributed Statistical Computing (DSC 2003)",
  address      = "Vienna, Austria",
  editor       = "Kurt Hornik and Friedrich Leisch and Achim Zeileis",
  month        = "March",
  year         = "2003",
  issn         = "1609-395X",
  howpublished = "http://www.ci.tuwien.ac.at/Conferences/DSC-2003/"


[1] John M. Chambers, The methods package, R distribution, CRAN, 2002.
[2] Henrik Bengtsson, Programming with References - a case study using the R.oo package, Division for Mathematical Statistics, Centre for Mathematical Sciences, Lund University, Sweden, 2002.
[3] John Chambers, OOP Programming in the S Language, Omegahat, 2002.
[4] UML Resource Page, Object Management Group, 2002.
[5] Henrik Bengtsson, R Coding Conventions (RCC) (draft), Mathematical Statistics, Centre for Mathematical Sciences, Lund University, Sweden.
[6] Henrik Bengtsson, Safely creating S3 generic functions using setGenericS3(), Division for Mathematical Statistics, Centre for Mathematical Sciences, Lund University, Sweden, 2002.
[7] Henrik Bengtsson, com.braju.sma - object-oriented microarray analysis in 100% R, Division for Mathematical Statistics, Centre for Mathematical Sciences, Lund University, Sweden, 2002.
[8] R Development Core Team, R Language Definition, ISBN 3-901167-56-0.
[9] Henrik Bengtsson, Object-oriented programming and programming style guidelines for R, H. Bengtsson, Talk at Bioinformatics Group, Walter & Eliza Hall Institute of Medical Research, Melbourne, October 16, 2002.
[10] Henrik Bengtsson, The R.oo package - Object-oriented programming with references using standard R code, Talk at the DSC 2003 conference, Wienna, March 22, 2003.