Unlike S3 classes and
objects
which lacks formal definition, we look at S4 class which is stricter in the
sense that it has a formal definition and a uniform way to create objects.
This adds safety to our code and prevents us from accidentally making naive mistakes.
How to define S4 Class?
S4 class is defined using the setClass()
function.
In R terminology, member variables are called slots. While defining a class, we need to set the name and the slots (along with class of the slot) it is going to have.
Example 1: Definition of S4 class
setClass("student", slots=list(name="character", age="numeric", GPA="numeric"))
In the above example, we defined a new class called student
along
with three slots it's going to have name
, age
and
GPA
.
There are other optional arguments of setClass()
which you can
explore in the help section with ?setClass
.
How to create S4 objects?
S4 objects are created using the new()
function.
Example 2: Creation of S4 object
> # create an object using new()
> # provide the class name and value for slots
> s <- new("student",name="John", age=21, GPA=3.5)
> s
An object of class "student"
Slot "name":
[1] "John"
Slot "age":
[1] 21
Slot "GPA":
[1] 3.5
We can check if an object is an S4 object through the function
isS4()
.
> isS4(s)
[1] TRUE
The function setClass()
returns a generator function.
This generator function (usually having same name as the class) can be used to create new objects. It acts as a constructor.
> student <- setClass("student", slots=list(name="character", age="numeric", GPA="numeric"))
> student
class generator function for class "student" from package '.GlobalEnv'
function (...)
new("student", ...)
Now we can use this constructor function to create new objects.
Note above that our constructor in turn uses the new()
function
to create objects. It is just a wrap around.
Example 3: Creation of S4 objects using generator function
> student(name="John", age=21, GPA=3.5)
An object of class "student"
Slot "name":
[1] "John"
Slot "age":
[1] 21
Slot "GPA":
[1] 3.5
How to access and modify slot?
Just as components of a
list are accessed using
$
, slot of an object are accessed using @
.
Accessing slot
> s@name
[1] "John"
> s@GPA
[1] 3.5
> s@age
[1] 21
Modifying slot directly
A slot can be modified through reassignment.
> # modify GPA
> s@GPA <- 3.7
> s
An object of class "student"
Slot "name":
[1] "John"
Slot "age":
[1] 21
Slot "GPA":
[1] 3.7
Modifying slots using slot() function
Similarly, slots can be access or modified using the
slot()
function.
> slot(s,"name")
[1] "John"
> slot(s,"name") <- "Paul"
> s
An object of class "student"
Slot "name":
[1] "Paul"
Slot "age":
[1] 21
Slot "GPA":
[1] 3.7
Methods and Generic Functions
As in the case of S3 class, methods for S4 class also belong to generic functions rather than the class itself. Working with S4 generics is pretty much similar to S3 generics.
You can list all the S4 generic functions and methods available, using the
function showMethods()
.
Example 4: List all generic functions
> showMethods()
Function: - (package base)
Function: != (package base)
...
Function: trigamma (package base)
Function: trunc (package base)
Writing the name of the object in interactive mode prints it. This is done
using the S4 generic function show()
.
You can see this function in the above list. This function is the S4 analogy
of the S3 print()
function.
Example 5: Check if a function is a generic function
> isS4(print)
[1] FALSE
> isS4(show)
[1] TRUE
We can list all the methods of show generic function using
showMethods(show)
.
Example 6: List all methods of a generic function
> showMethods(show)
Function: show (package methods)
object="ANY"
object="classGeneratorFunction"
...
object="standardGeneric"
(inherited from: object="genericFunction")
object="traceable"
How to write your own method?
We can write our own method using setMethod()
helper function.
For example, we can implement our class method for the
show()
generic as follows.
setMethod("show",
"student",
function(object) {
cat(object@name, "\n")
cat(object@age, "years old\n")
cat("GPA:", object@GPA, "\n")
}
)
Now, if we write out the name of the object in interactive mode as before, the above code is executed.
> s <- new("student",name="John", age=21, GPA=3.5)
> s # this is same as show(s)
John
21 years old
GPA: 3.5
In this way we can write our own S4 class methods for generic functions.