R6 Classes and Their Types
In Object-Oriented Programming (OOP) within the R language, encapsulation refers to bundling data and methods within a class. The R6 package in R provides an encapsulated OOP framework, enabling the use of encapsulation effectively. The R6 package offers R6 classes, which function similarly to reference classes but are independent of S4 classes. In the R6 system, you define a class by creating a new R6Class object, specifying the class name, and including a list of properties and methods. Properties can be any R object, while methods are functions that interact with objects of the class.
To create an instance of an R6 class, you use the $new() method, passing any initial values for the properties. Once an object is instantiated, you can call its methods and access or modify its properties using the $ operator.
A key feature of R6 is its support for encapsulation and information hiding. This allows internal object details to remain hidden, simplifying the creation of complex and robust programs.
R6 classes allow for organizing code efficiently, enabling the creation of custom objects with their own properties and behaviors. Additionally, R6 supports inheritance, even across classes defined in different packages. Prominent R packages like dplyr and shiny utilize R6 classes.
Example: Basic R6 Class Implementation
library(R6)
# Define a Stack class
Stack <- R6Class("Stack",
# Public members
public = list(
# Constructor/initializer
initialize = function(...) {
private$items <- list(...)
},
# Push an item onto the stack
push = function(item) {
private$items <- append(private$items, item)
},
# Pop an item from the stack
pop = function() {
if (self$size() == 0)
stop("Stack is empty")
item <- private$items[[length(private$items)]]
private$items <- private$items[-length(private$items)]
item
},
# Get the number of items in the stack
size = function() {
length(private$items)
}
),
# Private members
private = list(
items = list()
)
)
# Create a Stack object
StackObject <- Stack$new()
# Push 10 onto the stack
StackObject$push(10)
# Push 20 onto the stack
StackObject$push(20)
# Pop the top item (20)
StackObject$pop()
# Pop the remaining item (10)
StackObject$pop()
Output:
[1] 20
[1] 10
In this example, the stack is implemented with private storage (items) that is hidden from external modification. The initialize method acts as the constructor, and public methods like push and pop provide controlled access to the stack.
Example: Inheritance in R6 Classes
# Define a subclass of Stack
ExtendedStack <- R6Class("ExtendedStack",
# Inherit the Stack class
inherit = Stack,
public = list(
# Override the size method to display a message
size = function() {
message("Calculating stack size...")
super$size() # Call the size method of the superclass
}
)
)
# Create an ExtendedStack object
ExtendedStackObject <- ExtendedStack$new()
# Push 5 onto the stack
ExtendedStackObject$push(5)
# Push 15 onto the stack
ExtendedStackObject$push(15)
# Check the stack size (with a message)
ExtendedStackObject$size()
# Pop the top item (15)
ExtendedStackObject$pop()
# Pop the remaining item (5)
ExtendedStackObject$pop()
Output:
[1] 20
[1] 10
In this example, the stack is implemented with private storage (items) that is hidden from external modification. The initialize method acts as the constructor, and public methods like push and pop provide controlled access to the stack.
Example: Inheritance in R6 Classes
# Define a subclass of Stack
ExtendedStack <- R6Class("ExtendedStack",
# Inherit the Stack class
inherit = Stack,
public = list(
# Override the size method to display a message
size = function() {
message("Calculating stack size...")
super$size() # Call the size method of the superclass
}
)
)
# Create an ExtendedStack object
ExtendedStackObject <- ExtendedStack$new()
# Push 5 onto the stack
ExtendedStackObject$push(5)
# Push 15 onto the stack
ExtendedStackObject$push(15)
# Check the stack size (with a message)
ExtendedStackObject$size()
# Pop the top item (15)
ExtendedStackObject$pop()
# Pop the remaining item (5)
ExtendedStackObject$pop()
Output:
Calculating stack size...
[1] 2
[1] 15
[1] 5
In this example, the ExtendedStack class inherits from the Stack class. It overrides the size method to include a message while still calling the original method using super. This demonstrates how methods from the parent class can be extended or customized in the subclass.
Key Features of R6 Classes
- Encapsulation: Private members (e.g.,
private$items) ensure internal object details are protected from external modification. - Public and Private Members: Public members are accessible using
$, while private members are accessible only within class methods. - Inheritance: Subclasses can inherit properties and methods from parent classes, and
superallows access to parent methods. - Initialization: The
initializemethod acts as a constructor for setting up objects.
These features make R6 a robust and flexible system for implementing OOP in R.
Leave a Reply