Chapter 53 R6 and S4 Systems

What You’ll Learn:

  • R6 classes (mutable objects)
  • S4 system (formal OOP)
  • When to use each
  • Common errors

Difficulty: ⭐⭐⭐ Advanced

53.1 R6 Classes

R6 provides mutable, encapsulated objects:

library(R6)

# Define R6 class
Person <- R6Class("Person",
  public = list(
    name = NULL,
    age = NULL,
    
    initialize = function(name, age) {
      self$name <- name
      self$age <- age
    },
    
    greet = function() {
      paste("Hello, I'm", self$name)
    },
    
    birthday = function() {
      self$age <- self$age + 1
      invisible(self)
    }
  )
)

# Create instance
alice <- Person$new("Alice", 30)
alice$greet()
#> [1] "Hello, I'm Alice"
alice$birthday()
alice$age  # Now 31 (mutable!)
#> [1] 31

53.2 S4 System

S4 provides formal class definitions:

# Define S4 class
setClass("PersonS4",
  slots = list(
    name = "character",
    age = "numeric"
  )
)

# Create instance
alice_s4 <- new("PersonS4", name = "Alice", age = 30)

# Define method
setGeneric("greet", function(x) standardGeneric("greet"))
#> [1] "greet"
setMethod("greet", "PersonS4", function(x) {
  paste("Hello", x@name)
})

greet(alice_s4)
#> [1] "Hello Alice"

53.3 When to Use Each

System Use When
S3 Simple classes, R-like feel
R6 Mutable state, encapsulation
S4 Formal definitions, Bioconductor

53.4 Summary

Key Takeaways:

  1. R6 - Mutable objects with encapsulation
  2. S4 - Formal OOP with type checking
  3. S3 - Still most common for simple cases
  4. Choose based on needs - Each has trade-offs

Quick Reference:

# R6
MyClass <- R6Class("MyClass",
  public = list(
    initialize = function() {},
    method = function() {}
  )
)
obj <- MyClass$new()

# S4
setClass("MyClass", slots = list(x = "numeric"))
obj <- new("MyClass", x = 1)