Writing S3 Classes
S3 classes in R are defined informally and don’t require explicit class definitions. Instead, you work with lists and use the class attribute to set the class of an object. Here’s a step-by-step approach to creating and managing S3 classes.
Define a Constructor Function
A constructor function creates objects of a specific S3 class. It initializes the object and sets the class attribute.
Example: Creating a Person Class
# Define a constructor for the Person class create_person <- function(name, age) { # Create a list with the attributes obj <- list(name = name, age = age) # Set the class attribute class(obj) <- "Person" return(obj) } # Create an instance of the Person class alice <- create_person("Alice", 30)
Define Methods for the S3 Class
Methods are functions that operate on objects of a specific class. They are named with the pattern function_name.class_name.
Example: Defining a Print Method
# Define a print method for the Person class print.Person <- function(x) { cat("Name:", x$name, "\nAge:", x$age, "\n") } # Use the print method print(alice) # Calls print.Person
Define Generic Functions
Generic functions dispatch methods based on the class of the object. You define a generic function and its methods separately.
Example: Creating a Generic describe Function
# Define a generic function describe <- function(x) { UseMethod("describe") } # Define a method for the Person class describe.Person <- function(x) { cat("Description:\n") cat("Name:", x$name, "\nAge:", x$age, "\n") } # Use the describe function describe(alice) # Calls describe.Person
Handle Inheritance in S3
S3 supports multiple inheritance by assigning multiple classes to an object. Methods are called in the order of the classes.
Example: Adding a Student Class
Create a Student Class
# Define a constructor for Student, inheriting from Person create_student <- function(name, age, student_id) { obj <- create_person(name, age) obj$student_id <- student_id class(obj) <- c("Student", "Person") return(obj) } # Create an instance of Student charlie <- create_student("Charlie", 22, "S123")
Define Methods for the Student Class
# Define a print method for Student print.Student <- function(x) { print.Person(x) # Call the print method for Person cat("Student ID:", x$student_id, "\n") } # Use the print method for Student print(charlie) # Calls print.Student
Extend Functionality with New Methods
You can extend your S3 class functionality by adding new methods or modifying existing ones.
Example: Adding a Summary Method
# Define a generic summary function summary <- function(x) { UseMethod("summary") } # Define a summary method for Person summary.Person <- function(x) { cat("Summary of Person:\n") cat("Name:", x$name, "\nAge:", x$age, "\n") } # Define a summary method for Student summary.Student <- function(x) { summary.Person(x) # Call summary.Person cat("Student ID:", x$student_id, "\n") } # Use the summary function summary(charlie) # Calls summary.Student
Managing S3 Objects
S3 objects can be managed using standard R functions like ls(), rm(), save(), and exists().
Example: Managing S3 Objects
List All Objects:
# List objects in the environment ls()
Remove an Object:
# Remove the object charlie rm(charlie)
Save Objects:
# Save the objects to a file save(alice, file = "people.RData")
Check for Existence of an Object:
# Check if the object alice exists exists("alice")
Conclusion
Writing S3 classes in R involves defining constructors, methods, and generic functions, as well as managing inheritance and extending functionality. This approach provides a flexible and simple way to implement object-oriented programming in R, allowing for custom object management and method dispatch tailored to specific needs.