Object-Oriented programming in R

We use it without knowing it, nor worrying about it.
A bit of vocabulary : object, class, attribute, method, inheritance, polymorphism.

Two frameworks:

  • S3 (“old-style”, widely used in base packages)
  • S4 (“formal classes”, since R 1.7, widely used in Bioconductor).

Another framework called R5 is under development.


S3 framework

A 'class' is a label attached to an object. Every object in R has a class (“numeric”, “matrix”, “lm”, “factor”…).

Method dispatch

Example of the summary() function. Applied on different objects gives different outputs. Many summary.“classname”() defined, for each class.

summary
## function (object, ...) 
## UseMethod("summary")
## <bytecode: 0xaa03898>
## <environment: namespace:base>
methods("summary")
##  [1] summary.aov                  summary.aovlist             
##  [3] summary.aspell*              summary.connection          
##  [5] summary.data.frame           summary.Date                
##  [7] summary.default              summary.ecdf*               
##  [9] summary.factor               summary.ggplot*             
## [11] summary.glm                  summary.infl                
## [13] summary.lm                   summary.loess*              
## [15] summary.loglm*               summary.manova              
## [17] summary.matrix               summary.mlm                 
## [19] summary.negbin*              summary.nls*                
## [21] summary.packageStatus*       summary.PDF_Dictionary*     
## [23] summary.PDF_Stream*          summary.polr*               
## [25] summary.POSIXct              summary.POSIXlt             
## [27] summary.ppr*                 summary.prcomp*             
## [29] summary.princomp*            summary.rlm*                
## [31] summary.srcfile              summary.srcref              
## [33] summary.stepfun              summary.stl*                
## [35] summary.table                summary.tukeysmooth*        
## [37] summary.XMLInternalDocument*
## 
##    Non-visible functions are asterisked

Non-visible functions can be accessed by getAnywhere(“functionname”)

summary.loess()
## Error: impossible de trouver la fonction "summary.loess"
getAnywhere(summary.loess)
## A single object matching 'summary.loess' was found
## It was found in the following places
##   registered S3 method for summary from namespace stats
##   namespace:stats
## with value
## 
## function (object, ...) 
## {
##     class(object) <- "summary.loess"
##     object
## }
## <bytecode: 0xb0a0108>
## <environment: namespace:stats>

Access all methods of a class.

methods(class = "lm")
##  [1] add1.lm*           alias.lm*          anova.lm          
##  [4] case.names.lm*     confint.lm*        cooks.distance.lm*
##  [7] deviance.lm*       dfbeta.lm*         dfbetas.lm*       
## [10] drop1.lm*          dummy.coef.lm*     effects.lm*       
## [13] extractAIC.lm*     family.lm*         formula.lm*       
## [16] fortify.lm*        hatvalues.lm       influence.lm*     
## [19] kappa.lm           labels.lm*         logLik.lm*        
## [22] model.frame.lm     model.matrix.lm    nobs.lm*          
## [25] plot.lm            predict.lm         print.lm          
## [28] proj.lm*           qr.lm*             residuals.lm      
## [31] rstandard.lm       rstudent.lm        simulate.lm*      
## [34] summary.lm         variable.names.lm* vcov.lm*          
## 
##    Non-visible functions are asterisked

Creating an S3 object

Example of the mygsea2 package.

# Create a list
z <- list()
# Label it with the correct class
class(z) <- "gsea"
# Create the methods the user of the class/object will need
print.gsea <- function(object) {
}
# If needed, create a new generic method
reduce.gsea <- function(object) {
}
reduce <- function(object) UseMethod("reduce")

Caution : the user can easily access attributes directly, modify them… and R will not complain!


S4 framework

Based on the same “method dispatch” idea than S3, but more formal.

setClass("GSEA", representation(nperms = "numeric"), contains = "genelist", 
    validity = function(object) {
    })
gsea <- new("GSEA", nperms = 1000)

Checks are made for the validity of any created object. Properties include a name, representation, inheritance, prototype, validation(), etc. Attributes are stored in slots, similar to the components of a list for a S3 object, but use @ to “enter” the attributes of an object. S3 use print(), S4 use show(). “ANY” is the basic inheritance.

One can choose whichever one wants, but in any case, avoid mixing S3 and S4.

How to access information in an unknown object?

  • class(object)
  • look at documentation
  • find if S3 or S4 with names(object) or isS4(object)
  • look at the methods available for the object with methods(class=“class”) or showMethods(class=“class”)
  • look at the attributes using $ or @
  • if needed, look at a method's source code to see how it handles the attributes (method.class or getMethods(“method”, “class”) )

R5 framework

Still under development… See ?ReferenceClasses and http://adv-r.had.co.nz/R5.html


Creative Commons License
This work by Celine Hernandez is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.