0% found this document useful (0 votes)
13 views33 pages

Unit 3

Object-Oriented Programming (OOP) in R utilizes S3 and S4 systems to manage complexity in coding. S3 is a simpler, informal class system that allows function overloading and method dispatching, while S4 is more formal with defined class structures and supports multiple dispatches. Both systems enable the creation of objects and classes, with S3 being more flexible and S4 offering more structure.

Uploaded by

gayathrinaik12
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views33 pages

Unit 3

Object-Oriented Programming (OOP) in R utilizes S3 and S4 systems to manage complexity in coding. S3 is a simpler, informal class system that allows function overloading and method dispatching, while S4 is more formal with defined class structures and supports multiple dispatches. Both systems enable the creation of objects and classes, with S3 being more flexible and S4 offering more structure.

Uploaded by

gayathrinaik12
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 33

What is Object-Oriented Programming in R?

Object-Oriented Programming (OOP) is the most popular programming language. With the help of oops
concepts, we can construct the modular pieces of code which are used to build blocks for large systems. R is a
functional language, and we can do programming in oops style. In R, oops is a great tool to manage the
complexity of larger programs.

In Object-Oriented Programming, S3 and S4 are the two important systems.

S3

In oops, the S3 is used to overload any function. So that we can call the functions with different names and it
depends on the type of input parameter or the number of parameters.

S4 is the most important characteristic of oops. However, this is a limitation, as it is quite difficult to debug.
There is an optional reference class for S4.

Objects and Classes in R


In R, everything is an object. Therefore, programmers perform OOPS concept when they write code in R. An
object is a data structure which has some methods that can act upon its attributes.

In R, classes are the outline or design for the object. Classes encapsulate the data members, along with the
functions. In R, there are two most important classes, i.e., S3 and S4, which play an important role in
performing OOPs concepts.

Let's discuss both the classes one by one with their examples for better understanding.

1) S3 Class

With the help of the S3 class, we can take advantage of the ability to implement the generic function OO.
Furthermore, using only the first argument, S3 is capable of dispatching. S3 differs from traditional
programming languages such as Java, C ++, and C #, which implement OO passing messages. This makes S3
easy to implement. In the S3 class, the generic function calls the method. S3 is very casual and has no formal
definition of classes.

ADVERTISEMENT
S3 requires very little knowledge from the programmer.

Creating an S3 class

In R, we define a function which will create a class and return the object of the created class. A list is made with
relevant members, class of the list is determined, and a copy of the list is returned. There is the following
syntax to create a class

1. variable_name <- list(member1, member2, member3.........memberN)

Example

1. s <- list(name = "Ram", age = 29, GPA = 4.0)


2. class(s) <- "Faculty"
3. s

Output

There is the following way in which we define our generic function print.

1. print
2. function(x, ...)
3. UseMethod("Print")

When we execute or run the above code, it will give us the following output:
Like print function, we will make a generic function GPA to assign a new value to our GPA member. In the
following way we will make the generic function GPA

1. GPA <- function(obj1){


2. UseMethod("GPA")
3. }

Once our generic function GPA is created, we will implement a default function for it

1. GPA.default <- function(obj){


2. cat("We are entering in generic function\n")
3. }

After that we will make a new method for our GPA function in the following way

1. GPA.faculty <- function(obj1){


2. cat("Final GPA is ",obj1$GPA,"\n")
3. }

And at last we will run the method GPA as

1. GPA(s)

Output
Inheritance in S3

Inheritance means extracting the features of one class into another class. In the S3 class of R, inheritance is
achieved by applying the class attribute in a vector.

For inheritance, we first create a function which creates new object of class faculty in the following way

1. faculty<- function(n,a,g) {
2. value <- list(nname=n, aage=a, GPA=g)
3. attr(value, "class") <- "faculty"
4. value
5. }

After that we will define a method for generic function print() as

1. print.student <- function(obj1) {


2. cat(1obj$name, "\n")
3. cat(1obj$age, "years old\n")
4. cat("GPA:", obj1$GPA, "\n")
5. }

Now, we will create an object of class InternationalFaculty which will inherit from faculty class. This process will
be done by assigning a character vector of class name as:

1. class(Objet) <- c(child, parent)

so,

1. # create a list
2. fac <- list(name="Shubham", age=22, GPA=3.5, country="India")
3. # make it of the class InternationalFaculty which is derived from the class Faculty
4. class(fac) <- c("InternationalFaculty","Faculty")
5. # print it out
6. fac

When we run the above code which we have discussed, it will generate the following output:
We can see above that, we have not defined any method of form print. InternationalFaculty (), the method
called print.Faculty(). This method of class Faculty was inherited.

So our next step is to defined print.InternationalFaculty() in the following way:

1. print.InternationalFaculty<- function(obj1) {
2. cat(obj1$name, "is from", obj1$country, "\n")
3. }

The above function will overwrite the method defined for class faculty as

1. Fac
getS3method and getAnywhere function

There are the two most common and popular S3 method functions which are used in R. The first method
is getS3method() and the second one is getAnywhere().

S3 finds the appropriate method associated with a class, and it is useful to see how a method is implemented.
Sometimes, the methods are non-visible, because they are hidden in a namespace. We use getS3method or
getAnywhere to solve this problem.

getS3method

getAnywhere function

1. getAnywhere("simpleloess")

2) S4 Class

The S4 class is similar to the S3 but is more formal than the latter one. It differs from S3 in two different ways.
First, in S4, there are formal class definitions which provide a description and representation of classes. In
addition, it has special auxiliary functions for defining methods and generics. The S4 also offers multiple
dispatches. This means that common functions are capable of taking methods based on multiple arguments
which are based on class.

Creating an S4 class

In R, we use setClass() command for creating S4 class. In S4 class, we will specify a function for verifying the
data consistency and also specify the default value. In R, member variables are called slots.

To create an S3 class, we have to define the class and its slots. There are the following steps to create an S4
class

Step 1:

In the first step, we will create a new class called faculty with three slots name, age, and GPA.

1. setClass("faculty", slots=list(name="character", age="numeric", GPA="numeric"))

There are many other optional arguments of setClass() function which we can explore by using ?
setClass command.

Step 2:

In the next step, we will create the object of S4 class. R provides new() function to create an object of S4 class.
In this new function we pass the class name and the values for the slots in the following way:

1. setClass("faculty", slots=list(name="character", age="numeric", GPA="numeric"))


2. # creating an object using new()
3. # providing the class name and value for slots
4. s <- new("faculty",name="Shubham", age=22, GPA=3.5)
5. s

It will generate the following output

Creating S4 objects using a generator function

The setClass() function returns a generator function. This generator function helps in creating new objects. And
it acts as a constructor.

1. A <- setClass("faculty", slots=list(name="character", age="numeric", GPA="numeric"))


2. A

It will generate the following output:

Now we can use the above constructor function to create new objects. The constructor in turn uses the new()
function to create objects. It is just a wrap around. Let's see an example to understand how S4 object is created
with the help of generator function.
Example

1. faculty<-setClass("faculty", slots=list(name="character", age="numeric", GPA="numeric"))


2. # creating an object using generator() function
3. # providing the class name and value for slots
4. faculty(name="Shubham", age=22, GPA=3.5)

Output

Inheritance in S4 class

Like S3 class, we can perform inheritance in S4 class also. The derived class will inherit both attributes and
methods of the parent class. Let's start understanding that how we can perform inheritance in S4 class. There
are the following ways to perform inheritance in S4 class:

Step 1:

In the first step, we will create or define class with appropriate slots in the following way:

1. setClass("faculty",
2. slots=list(name="character", age="numeric", GPA="numeric")
3. )

Step 2:

After defining class, our next step is to define class method for the display() generic function. This will be done
in the following manner:

1. setMethod("show",
2. "faculty",
3. function(obj) {
4. cat(obj@name, "\n")
5. cat(obj@age, "years old\n")
6. cat("GPA:", obj@GPA, "\n")
7. }
8. )
Step 3:

In the next step, we will define the derived class with the argument contains. The derived class is defined in the
following way

1. setClass("Internationalfaculty",
2. slots=list(country="character"),
3. contains="faculty"
4. )

In our derived class we have defined only one attribute i.e. country. Other attributes will be inherited from its
parent class.

1. s <- new("Internationalfaculty",name="John", age=21, GPA=3.5, country="India")


2. show(s)

When we did show(s), the method defines for class faculty gets called. We can also define methods for the
derived class of the base class as in the case of the S3 system.

In R, the concept of object-oriented programming is implemented through various systems such as


S3, S4, and Reference Classes (R5). Here, I'll provide an overview of class definition, creating objects,
methods, and generic functions using S3 and S4 systems.

### S3 System

#### Class Definition

In S3, classes are defined implicitly by setting the `class` attribute of an object.

```R

# Creating an object and assigning a class

dog <- list(name = "Dog", age = 5)


class(dog) <- "Animal"

```

#### Creating Objects from Constructors

A constructor function can be used to create objects of a class.

```R

# Constructor function

create_animal <- function(name, age) {

obj <- list(name = name, age = age)

class(obj) <- "Animal"

return(obj)

# Creating objects

dog <- create_animal("Dog", 5)

cat <- create_animal("Cat", 3)

```

#### Methods

Methods for S3 classes are defined by naming conventions.

```R

# Defining a method for class "Animal"

print.Animal <- function(obj) {

cat("Name:", obj$name, "\nAge:", obj$age, "\n")

# Using the method


print(dog) # Output: Name: Dog Age: 5

```

#### Generic Functions

Generic functions dispatch the appropriate method based on the class of the object.

```R

# Defining a generic function

make_sound <- function(obj, sound) UseMethod("make_sound")

# Defining a method for the generic function

make_sound.Animal <- function(obj, sound) {

paste(obj$name, "says", sound)

# Using the generic function

make_sound(dog, "Woof") # Output: "Dog says Woof"

```

### S4 System

S4 is a more formal and rigorous system for object-oriented programming in R.

#### Class Definition

In S4, classes are explicitly defined using the `setClass` function.

```R

# Defining a class

setClass("Animal",
slots = list(name = "character", age = "numeric"))

```

#### Creating Objects from Constructors

Objects are created using the `new` function.

```R

# Creating objects

dog <- new("Animal", name = "Dog", age = 5)

cat <- new("Animal", name = "Cat", age = 3)

```

#### Methods

Methods are defined using the `setMethod` function.

```R

# Defining a method

setMethod("show", "Animal",

function(object) {

cat("Name:", object@name, "\nAge:", object@age, "\n")

})

# Using the method

show(dog) # Output: Name: Dog Age: 5

```

#### Generic Functions

Generic functions are defined using the `setGeneric` function.


```R

# Defining a generic function

setGeneric("make_sound", function(object, sound) standardGeneric("make_sound"))

# Defining a method for the generic function

setMethod("make_sound", "Animal",

function(object, sound) {

paste(object@name, "says", sound)

})

# Using the generic function

make_sound(dog, "Woof") # Output: "Dog says Woof"

```

### Summary

1. **Class Definition**:

- S3: Implicit by setting the `class` attribute.

- S4: Explicit using `setClass`.

2. **Creating Objects from Constructors**:

- S3: Constructor function sets the class.

- S4: Use `new` function to create objects.

3. **Methods**:

- S3: Defined by naming convention (e.g., `print.Animal`).

- S4: Defined using `setMethod`.

4. **Generic Functions**:

- S3: Use `UseMethod` for dispatch.


- S4: Use `setGeneric` for defining generic functions and `setMethod` for methods.

Both S3 and S4 have their use cases, with S3 being simpler and more flexible, while S4 provides more
rigor and structure.

R Classes and Objects


In this article, you will be introduced to all three classes (S3, S4 and
reference class) in R programming with the help of examples.

We can do object oriented programming in R. In fact, everything in R is an


object.

An object is a data structure having some attributes and methods which act
on its attributes.

Class is a blueprint for the object. We can think of class like a sketch
(prototype) of a house. It contains all the details about the floors, doors,
windows etc. Based on these descriptions we build the house.

House is the object. As many houses can be made from a description, we


can create many objects from a class. An object is also called an instance
of a class and the process of creating this object is called instantiation.

While most programming languages have a single class system, R has


three class systems. Namely, S3, S4 and more recently Reference class
systems.

They have their own features and peculiarities and choosing one over the
other is a matter of preference. Below, we give a brief introduction to them.
S3 Class
S3 class is somewhat primitive in nature. It lacks a formal definition and
objects of this class can be created simply by adding a class attribute to it.

This simplicity accounts for the fact that it is widely used in the R
programming language. In fact most of the R built-in classes are of this
type.

See R programming S3 Class section for further details.

Example 1: S3 Class

s <- list(name = "John", age = 21, GPA = 3.5)


class(s) <- "student"

# print the list with the updated class


print(s)

Output

$name
[1] "John"

$age
[1] 21

$GPA
[1] 3.5

attr(,"class")
[1] "student"

Here, the class attribute allows objects to be associated with a specific


class. The class attribute provides a way to define behavior and methods
for objects of that class.
By assigning the class attribute to the list s, we are essentially indicating
that s is an object of the "student" class within the S3 object-oriented
system.

S4 Class
S4 class is an improvement over the S3 class. They have a formally
defined structure which helps in making objects of the same class look
more or less similar.

Class components are properly defined using the setClass() function and
objects are created using the new() function.
See R programming S4 Class section for further details.

Example 2: S4 class

setClass("student", slots = list(name = "character", age = "numeric",


GPA = "numeric"))

# create an instance of the "student" class


s <- new("student", name = "John", age = 21, GPA = 3.5)

# print the instance


print(s)

Output

An object of class "student"


Slot "name":
[1] "John"

Slot "age":
[1] 21

Slot "GPA":
[1] 3.5

Here, the setClass() function is used to define an S4 class


called "student" with three slots: name of type "character", age of
type "numeric", and GPA of type "numeric".
After defining the class, we have created an instance of the "student" class
using the new() function.
The new() function takes the class name and initializes the object by
providing values for each slot.
Finally, the instance s is printed, displaying the object's class and the
values stored in each slot.

Reference Class
Reference classes were introduced later, compared to the other two. It is
more similar to the object oriented programming we are used to seeing in
other major programming languages.

Reference classes are basically S4 classed with an environment added to


it.

See R programming Reference Class section for further details.


Example 3: Reference class

# define the reference class "student"


student <- setRefClass("student",
fields = list(
name = "character",
age = "numeric",
GPA = "numeric"
)
)

# create an instance of the "student" reference class


s <- student$new(
name = "John",
age = 21,
GPA = 3.5
)

# print the instance


print(s)

Output

Reference class object of class "student"


Field "name":
[1] "John"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

Here, we have defined the reference class "student" using


the setRefClass() function, specifying the class name and the fields within
the class.
The fields argument is a list that defines the names and types of the fields
in the class.
After defining the class, we have created an instance of the "student" class
using the $new() method.
The $new() method takes arguments for each field and initializes the object
with the provided values.
Finally, the instance s is printed, displaying the object's class and the
values stored in each field.

Comparison between S3 vs S4 vs Reference Class


S3 Class S4 Class Reference Class

Class defined using Class defined using


Lacks formal definition
setClass() setRefClass()

Objects are created by setting Objects are created Objects are created using
the class attribute using new() generator functions

Attributes are accessed using Attributes are accessed


Attributes are accessed using $
$ using @

Methods belong to generic Methods belong to


Methods belong to the class
function generic function

Follows copy-on-modify Follows copy-on- Does not follow copy-on-


semantics modify semantics modify semantics

R S3 Class
In this article, you will learn to work with S3 classes (one of the three class
systems in R programming).

S3 class is the most popular and prevalent class in R programming


language.

Most of the classes that come predefined in R are of this type. The fact that
it is simple and easy to implement is the reason behind this.
How to define S3 class and create S3 objects?
S3 class has no formal, predefined definition.

Basically, a list with its class attribute set to some class name, is an S3
object. The components of the list become the member variables of the
object.

Following is a simple example of how an S3 object of class student can be


created.

> # create a list with required components


> s <- list(name = "John", age = 21, GPA = 3.5)
> # name the class appropriately
> class(s) <- "student"
> # That's it! we now have an object of class "student"
> s
$name
[1] "John"
$age
[1] 21
$GPA
[1] 3.5
attr(,"class")
[1] "student"

This might look awkward for programmers coming from C++, Python etc.
where there are formal class definitions and objects have properly defined
attributes and methods.

In R S3 system, it's pretty ad hoc. You can convert an object's class


according to your will with objects of the same class looking completely
different. It's all up to you.
How to use constructors to create objects?
It is a good practice to use a function with the same name as class (not a
necessity) to create objects.

This will bring some uniformity in the creation of objects and make them
look similar.

We can also add some integrity check on the member attributes. Here is an
example. Note that in this example we use the attr() function to set the
class attribute of the object.

# a constructor function for the "student" class


student <- function(n,a,g) {
# we can add our own integrity checks
if(g>4 || g<0) stop("GPA must be between 0 and 4")
value <- list(name = n, age = a, GPA = g)
# class can be set using class() or attr() function
attr(value, "class") <- "student"
value
}

Here is a sample run where we create objects using this constructor.

> s <- student("Paul", 26, 3.7)


> s
$name
[1] "Paul"
$age
[1] 26
$GPA
[1] 3.7
attr(,"class")
[1] "student"
> class(s)
[1] "student"
> s <- student("Paul", 26, 5)
Error in student("Paul", 26, 5) : GPA must be between 0 and 4
> # these integrity check only work while creating the object using
constructor
> s <- student("Paul", 26, 2.5)
> # it's up to us to maintain it or not
> s$GPA <- 5

Methods and Generic Functions


In the above example, when we simply write the name of the object, its
internals get printed.

In interactive mode, writing the name alone will print it using


the print() function.

> s
$name
[1] "Paul"
$age
[1] 26
$GPA
[1] 3.7
attr(,"class")
[1] "student"

Furthermore, we can use print() with vectors, matrix, data


frames, factors etc. and they get printed differently according to the class
they belong to.
How does print() know how to print these variety of dissimilar looking
object?
The answer is, print() is a generic function. Actually, it has a collection of
a number of methods. You can check all these methods
with methods(print).
> methods(print)
[1] print.acf*
[2] print.anova*
...
[181] print.xngettext*
[182] print.xtabs*
Non-visible functions are asterisked

We can see methods like print.data.frame and print.factor in the above


list.
When we call print() on a data frame, it is dispatched
to print.data.frame().
If we had done the same with a factor, the call would dispatch
to print.factor(). Here, we can observe that the method names are in the
form generic_name.class_name(). This is how R is able to figure out which
method to call depending on the class.
Printing our object of class "student" looks for a method of the
form print.student(), but there is no method of this form.
So, which method did our object of class "student" call?
It called print.default(). This is the fallback method which is called if no
other match is found. Generic functions have a default method.
There are plenty of generic functions like print(). You can list them all
with methods(class="default").

> methods(class="default")
[1] add1.default* aggregate.default*
[3] AIC.default* all.equal.default
...

How to write your own method?


Now let us implement a method print.student() ourself.

print.student <- function(obj) {


cat(obj$name, "\n")
cat(obj$age, "years old\n")
cat("GPA:", obj$GPA, "\n")
}

Now this method will be called whenever we print() an object of class


"student".
In S3 system, methods do not belong to object or class, they belong to
generic functions. This will work as long as the class of the object is set.

> # our above implemented method is called


> s
Paul
26 years old
GPA: 3.7
> # removing the class attribute will restore as previous
> unclass(s)
$name
[1] "Paul"
$age
[1] 26
$GPA
[1] 3.7

Writing Your Own Generic Function


It is possible to make our own generic function like print() or plot(). Let us
first look at how these functions are implemented.

> print
function (x, ...)
UseMethod("print")
<bytecode: 0x0674e230>
<environment: namespace:base>
> plot
function (x, y, ...)
UseMethod("plot")
<bytecode: 0x04fe6574>
<environment: namespace:graphics>

We can see that they have a single call to UseMethod() with the name of the
generic function passed to it. This is the dispatcher function which will
handle all the background details. It is this simple to implement a generic
function.
For the sake of example, we make a new generic function called grade.

grade <- function(obj) {


UseMethod("grade")
}

A generic function is useless without any method. Let us implement the


default method.

grade.default <- function(obj) {


cat("This is a generic function\n")
}

Now let us make method for our class "student".

grade.student <- function(obj) {


cat("Your grade is", obj$GPA, "\n")
}

A sample run.

> grade(s)
Your grade is 3.7

In this way, we implemented a generic function called grade and later a


method for our class.
R S4 Class
In this article, you'll learn everything about S4 classes in R; how to define them, create them, access their slots,
and use them efficiently in your program.

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.

R Reference Class
Reference class in R programming is similar to the object oriented programming we are used to seeing in
common languages like C++, Java, Python etc.

Unlike S3 and S4 classes, methods belong to class rather than generic functions. Reference class are internally
implemented as S4 classes with an environment added to it.

How to define a reference class?


Defining reference class is similar to defining a S4 class. Instead of setClass() we use
the setRefClass() function.

> setRefClass("student")

Member variables of a class, if defined, need to be included in the class definition. Member variables of reference
class are called fields (analogous to slots in S4 classes).

Following is an example to define a class called student with 3 fields, name , age and GPA .

> setRefClass("student", fields = list(name = "character", age = "numeric", GPA = "numeric"))

How to create a reference objects?


The function setRefClass() returns a generator function which is used to create objects of that class.

> student <- setRefClass("student",


fields = list(name = "character", age = "numeric", GPA = "numeric"))
> # now student() is our generator function which can be used to create new objects
> s <- student(name = "John", age = 21, GPA = 3.5)
> s
Reference class object of class "student"
Field "name":
[1] "John"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

How to access and modify fields?


Fields of the object can be accessed using the $ operator.

> s$name
[1] "John"
> s$age
[1] 21
> s$GPA
[1] 3.5

Similarly, it is modified by reassignment.

> s$name <- "Paul"


> s
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

Warning Note

In R programming, objects are copied when assigned to new variable or passed to a function (pass by value).
For example.

> # create list a and assign to b


> a <- list("x" = 1, "y" = 2)
> b <- a
> # modify b
> b$y = 3
> # a remains unaffected
> a
$x
[1] 1
$y
[1] 2
> # only b is modified
> b
$x
[1] 1
$y
[1] 3

But this is not the case with reference objects. Only a single copy exist and all variables reference to the same
copy. Hence the name, reference.

> # create reference object a and assign to b


> a <- student(name = "John", age = 21, GPA = 3.5)
> b <- a
> # modify b
> b$name <- "Paul"
> # a and b both are modified
> a
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5
> b
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

This can cause some unwanted change in values and be the source of strange bugs. We need to keep this in
mind while working with reference objects. To make a copy, we can use the copy() method made availabe to us.

> # create reference object a and assign a's copy to b


> a <- student(name = "John", age = 21, GPA = 3.5)
> b <- a$copy()
> # modify b
> b$name <- "Paul"
> # a remains unaffected
> a
Reference class object of class "student"
Field "name":
[1] "John"
Field "age":
[1] 21
Field "GPA":
[1] 3.5
> # only b is modified
> b
Reference class object of class "student"
Field "name":
[1] "Paul"
Field "age":
[1] 21
Field "GPA":
[1] 3.5

Reference Methods
Methods are defined for a reference class and do not belong to generic functions as in S3 and S4 classes.

All reference class have some methods predefined because they all are inherited from the
superclass envRefClass .

> student
Generator for class "student":
Class fields:
Name: name age GPA
Class: character numeric numeric
Class Methods:
"callSuper", "copy", "export", "field", "getClass", "getRefClass",
"import", "initFields", "show", "trace", "untrace", "usingMethods"
Reference Superclasses:
"envRefClass"

We can see class methods like copy() , field() and show() in the above list. We can create our own methods for
the class.
This can be done during the class definition by passing a list of function definitions to methods argument
of setRefClass() .

student <- setRefClass("student",


fields = list(name = "character", age = "numeric", GPA = "numeric"),
methods = list(
inc_age = function(x) {
age <<- age + x
},
dec_age = function(x) {
age <<- age - x
}
)
)

In the above section of our code, we defined two methods called inc_age() and dec_age() . These two method
modify the field age .

Note that we have to use the non-local assignment operator <<- since age isn't in the method's local
environment. This is important.
Using the simple assignment operator <- would have created a local variable called age , which is not what we
want. R will issue a warning in such case.
Here is a sample run where we use the above defined methods.

> s <- student(name = "John", age = 21, GPA = 3.5)


> s$inc_age(5)
> s$age
[1] 26
> s$dec_age(10)
> s$age
[1] 16

You might also like