A system for doing object oriented programming
R is both interactive and has a system for object orientation.
S3 classes/methods
list with a class attribute on itS4 classes/methods
For now (and the forseeable future), S3 classes/methods and S4 classes/methods are separate systems (but they can be mixed to some degree).
Each system can be used fairly independently of the other.
Developers of new projects (you!) are encouraged to use the S4 style classes/methods.
A class is a description of an thing. A class can be
defined using setClass() in the methods package.
An object is an instance of a class. Objects can be created
using new().
A method is a function that only operates on a certain class of objects.
A generic function is an R function which dispatches methods. A
generic function typically encapsulates a "generic" concept
(e.g. plot, mean, predict, ...)
The help files for the methods package are extensive - do read
them as they are the primary documentation
You may want to start with ?Classes and ?Methods
Check out ?setClass, ?setMethod, and ?setGeneric
Use class? prefix for help on specific classes, e.g., class?GRanges
All objects in R have a class which can be determined by the class function
class(1)
## [1] "numeric"class(TRUE)
## [1] "logical"class(rnorm(100))
## [1] "numeric"class(NA)
## [1] "logical"class("foo")
## [1] "character"Data classes go beyond the atomic classes
x <- rnorm(100)y <- x + rnorm(100)fit <- lm(y ~ x) ## linear regression modelclass(fit)
## [1] "lm"names(fit)
## [1] "coefficients" "residuals" "effects" "rank" ## [5] "fitted.values" "assign" "qr" "df.residual" ## [9] "xlevels" "call" "terms" "model"isS4(fit)
## [1] FALSEgetClass("lm")
## Virtual Class "lm" [package "methods"]## ## Slots:## ## Name: .S3Class## Class: character## ## Extends: "oldClass"## ## Known Subclasses: ## Class "mlm", directly## Class "aov", directly## Class "glm", directly## Class "maov", by class "mlm", distance 2## Class "glm.null", by class "glm", distance 2S4 and S3 style generic functions look different but conceptually, they are the same (they play the same role).
When you program you can write new methods for an existing generic OR create your own generics and associated methods.
Of course, if a data type does not exist in R that matches your needs, you can always define a new class along with generics/methods that go with it
base package)The mean function is generic
mean
## function (x, ...) ## UseMethod("mean")## <bytecode: 0x7f90107b2a08>## <environment: namespace:base>So is the print function
print
## function (x, ...) ## UseMethod("print")## <bytecode: 0x7f8ff61573b0>## <environment: namespace:base>methods("mean")
## [1] mean.Date mean.default mean.difftime mean.POSIXct mean.POSIXlt ## [6] mean.quosure*## see '?methods' for accessing help and source codemethods package)The S4 equivalent of print is show
show
## standardGeneric for "show" defined from package "methods"## ## function (object) ## standardGeneric("show")## <bytecode: 0x7f8fe6a9a138>## <environment: 0x7f9006d7cee8>## Methods may be defined for arguments: object## Use showMethods(show) for currently available ones.## (This generic function excludes non-simple inheritance; see ?setIs)The show function is usually not called directly (much like
print) because objects are auto-printed
Think of S4 methods as simple functions that perform certain task depending on class
mimicMethod <- function(x) { if (is(x, "matrix")) method1(x) if (is(x, "data.frame")) method2(x) if (is(x, "IRanges")) method3(x)}The first argument of a generic function is an object of a particular class (there may be other arguments)
The generic function checks the class of the object.
A search is done to see if there is an appropriate method for that class.
If there exists a method for that class, then that method is called on the object and we're done.
If a method for that class does not exist, a search is done to see if there is a default method for the generic. If a default exists, then the default method is called.
If a default method doesn't exist, then an error is thrown.
Examining the code for an S3 or S4 method requires a call to a special function
You cannot just print the code for a method like other functions because the code for the method is usually hidden.
If you want to see the code for an S3 method, you can use the function
getS3method.
getS3method(<generic>, <class>)For S4 methods you can use the function getMethod
getMethod(<generic>, <signature>) (more
details later)> showMethods("mean")Function: mean (package base)x="ANY"x="AtomicList"x="CompressedIntegerList"x="CompressedLogicalList"x="CompressedNumericList"x="CompressedRleList"x="Rle"x="Views"What's happening here?
set.seed(2)x <- rnorm(100)mean(x)
## [1] -0.03069816numericnumeric objects!mean.getS3method("mean", "default")
## function (x, trim = 0, na.rm = FALSE, ...) ## {## if (!is.numeric(x) && !is.complex(x) && !is.logical(x)) {## warning("argument is not numeric or logical: returning NA")## return(NA_real_)## }## if (na.rm) ## x <- x[!is.na(x)]## if (!is.numeric(trim) || length(trim) != 1L) ## stop("'trim' must be numeric of length one")## n <- length(x)## if (trim > 0 && n) {## if (is.complex(x)) ## stop("trimmed means are not defined for complex data")## if (anyNA(x)) ## return(NA_real_)## if (trim >= 0.5) ## return(stats::median(x, na.rm = FALSE))## lo <- floor(n * trim) + 1## hi <- n + 1 - lo## x <- sort.int(x, partial = unique(c(lo, hi)))[lo:hi]## }## .Internal(mean(x))## }## <bytecode: 0x7f8fe606f2a8>## <environment: namespace:base>What happens here?
set.seed(3)df <- data.frame(x = rnorm(100), y = 1:100)sapply(df, mean)
## x y ## 0.01103557 50.50000000data.frame; in a data frame each column can be
an object of a different classsapply over the columns and call the mean functionmean checks the class of the object and
dispatches the appropriate method.numeric column and an integer
column; in both cases mean calls the default methodSome methods are visible to the user (i.e. mean.default)
You should never call methods directly
Use the generic function and let the method be dispatched automatically
The plot function is generic and its behavior depends on the
object.
set.seed(10)x <- rnorm(100)plot(x)

For time series objects, plot connects the dots
set.seed(10)x <- rnorm(100)y <- x + rnorm(100)fit <- lm(y ~ x) ## linear regression modelpar(mfrow = c(1, 4))plot(fit)

If you write new methods for new classes, you'll probably end up writing methods for the following generics:
There are two ways that you can extend the R system via classes/methods
print)Why would you want to create a new class?
To represent new types of data (e.g. gene expression, space-time, hierarchical, sparse matrices)
New concepts/ideas that haven't been thought of yet (e.g. a fitted point process model, mixed-effects model, a sparse matrix)
To abstract/hide implementation details from the user
A new class can be defined using the setClass function
At a minimum you need to specify the name of the class
You can also specify data elements that are called slots
You can then define methods for the class with the
setMethod function
Information about a class definition can be obtained with the
showClass function
Creating new classes/methods is usually not something done at the console; you likely want to save the code in a separate file
setClass("polygon", representation(x = "numeric", y = "numeric"))
The slots for this class are x and y. The slots for an
S4 object can be accessed with the @ operator.
You should never have to access slots directly. You should get/set data out of the class slot using the "accessor" functions (getters and setters).
plot method can be created with the setMethod
function.plot), and a class signature.setMethod("plot", "polygon", function(x, y, ...) { plot(x@x, x@y, type = "n", ...) xp <- c(x@x, x@x[1]) yp <- c(x@y, x@y[1]) lines(xp, yp) })
Note that the slots of the polygon (the x- and y-coordinates) are
accessed with the @ operator.
If things go well, you will not get any messages or errors and nothing
useful will be returned by either setClass or setMethod.
After calling setMethod the new plot method will be
added to the list of methods for plot.
showMethods("plot")
## Function: plot (package base)## x="ANY"## x="polygon"Note that the signature for class polygon is listed. The
method for ANY is the default method and it is what is called
when now other signature matches
p <- new("polygon", x = c(1, 2, 3, 4), y = c(1, 2, 3, 1))plot(p)

Class inheritance is used when you define a new class which “is almost like this other class but with a little twist”.
For example ExpressionSet inherits from eSet, and when you look at the class definition you cannot easily see a difference. The difference is that ExpressionSet is meant to contain expression data and has the exprs() accessor.
https://github.com/MalteThodberg/S4-Bioconductor - a collection of references by Malte Thodberg
https://github.com/nullranges/nullranges - an R package for generation of null ranges via bootstrapping or covariate matching
A system for doing object oriented programming
R is both interactive and has a system for object orientation.
Keyboard shortcuts
| ↑, ←, Pg Up, k | Go to previous slide |
| ↓, →, Pg Dn, Space, j | Go to next slide |
| Home | Go to first slide |
| End | Go to last slide |
| Number + Return | Go to specific slide |
| b / m / f | Toggle blackout / mirrored / fullscreen mode |
| c | Clone slideshow |
| p | Toggle presenter mode |
| t | Restart the presentation timer |
| ?, h | Toggle this help |
| Esc | Back to slideshow |