S3 Object System
The primary use of OO programming in R is for print, summary and plot methods. These methods allow us to have one generic function, e.g. print(), that displays the object differently depending on its type: printing a linear model is very different to printing a data frame.
The class of an object is determined by its classattribute:
Ex: create an object of class foo
x <- 1
attr(x, "class") <- "foo"
# or in one line
x <- structure(1, class = "foo")
# or better
class(x) <- "foo"
# nultiple classes in one object is also possible
class(x) <- c("A", "B")
S4 Object System
S4 classes has allowed us to construct rich and complicated data representations that nevertheless seems simple to the end user.
Let us look at a S3 object, the output of the linear model function lm in base R:
df <- data.frame(y = rnorm(10), x = rnorm(10))
lm.object <- lm(y ~ x, data = df)
lm.object
Call:
lm(formula = y ~ x, data = df)
Coefficients:
(Intercept) x
0.3147 -0.7131
names(lm.object)
[1] "coefficients" "residuals" "effects" "rank"
[5] "fitted.values" "assign" "qr" "df.residual"
[9] "xlevels" "call" "terms" "model"
class(lm.object)
[1] "lm"
In standard R, an S3 object is essentially a listwith a classattribute on it. The problem with S3 is that we can assign any class to any list, which is nonsense. Let us try an example
xx <- list(a = letters[1:3], b = rnorm(3))
class(xx) <- "lm"
xx
Call:
NULL
No coefficients
S4 classes have a formal definition and formal validity checking. To the end user, this gurantees validity of the object.
Seurat is an S4 class with several slots:
getClass("Seurat") :
Data inside an S4 class are organized into slots. You access slots by using either ‘@’ or the slots() function
slotNames(mouse_lung)
[1] "assays" "meta.data" "active.assay" "active.ident" "graphs"
[6] "neighbors" "reductions" "images" "project.name" "misc"
[11] "version" "commands" "tools"
Use is(mouse_lung) to inspect the classes of an S4 object; this example is a Seurat object.
[1] "Seurat"
mouse_lung@meta.data$test is equivalent to mouse_lung@meta.data[["test"]].
Seurat also provides mouse_lung[["NAME"]] accessors for assays and metadata. Assignment through mouse_lung[["TEST"]] <- uses the assigned value to determine the appropriate object component.
It occasionally happens that an S4 class definition gets updated. This might affect you in the following scenario
- You do an analysis in a given version of Bioconductor and you save your objects.
- 6 months later your work has to be revised, but Bioconductor has been updated in the meantime.
- When you
loadthe old object, it doesn’t seem to work. The solution to this problem is the functionupdateObject. When a programmer updates their class definition, they are supposed to provide anupdateObjectfunction which will update old objects to new objects. Note the “supposed”, this is not guranteed to happen, but feel free to report this as a bug if you encounter it.