R R6 Classes

R6 is a modern object-oriented system for R that brings features familiar from Python, Java, and other languages — mutable objects with public and private members, method chaining, and active bindings. R6 objects modify themselves in place rather than returning modified copies, which makes them efficient for stateful systems.

R6 vs S3 vs S4

Feature          S3        S4        R6
─────────────────────────────────────────────────────────────────
Mutable state    No        No        Yes (reference semantics)
Private fields   No        No        Yes
Method chaining  No        No        Yes (with invisible(self))
Encapsulation    Minimal   Partial   Full
Ease of use      Easy      Complex   Moderate

Installing and Loading R6

install.packages("R6")
library(R6)

Creating an R6 Class

library(R6)

Counter <- R6Class("Counter",
  public = list(
    count = 0,        # public field

    initialize = function(start=0) {
      self$count <- start
    },

    increment = function(by=1) {
      self$count <- self$count + by
      invisible(self)       # enables method chaining
    },

    reset = function() {
      self$count <- 0
      invisible(self)
    },

    print = function(...) {
      cat("Counter:", self$count, "\n")
      invisible(self)
    }
  )
)

c1 <- Counter$new(10)
c1$print()             # Counter: 10
c1$increment(5)
c1$print()             # Counter: 15

# Method chaining
c1$increment(3)$increment(2)$print()
# Counter: 20

Private Fields and Methods

BankAccount <- R6Class("BankAccount",
  private = list(
    balance = 0,          # not accessible from outside
    log_transaction = function(type, amount) {
      cat("[LOG]", type, "₹", amount, "| Balance: ₹", private$balance, "\n")
    }
  ),
  public = list(
    owner = NULL,

    initialize = function(owner, initial_balance=0) {
      self$owner     <- owner
      private$balance <- initial_balance
    },

    deposit = function(amount) {
      if (amount <= 0) stop("Amount must be positive")
      private$balance <- private$balance + amount
      private$log_transaction("DEPOSIT", amount)
      invisible(self)
    },

    withdraw = function(amount) {
      if (amount > private$balance) stop("Insufficient funds")
      private$balance <- private$balance - amount
      private$log_transaction("WITHDRAW", amount)
      invisible(self)
    },

    get_balance = function() private$balance,

    print = function(...) {
      cat("Account Owner:", self$owner, "\n")
      cat("Balance: ₹",    private$balance, "\n")
      invisible(self)
    }
  )
)

acc <- BankAccount$new("Asha", 10000)
acc$deposit(5000)$withdraw(2000)
acc$get_balance()   # 13000
acc$print()

Active Bindings — Computed Properties

Circle <- R6Class("Circle",
  private = list(r = 0),
  active = list(
    radius = function(value) {
      if (missing(value)) return(private$r)
      if (value < 0) stop("Radius must be non-negative")
      private$r <- value
    },
    area = function() pi * private$r^2,          # read-only
    circumference = function() 2 * pi * private$r  # read-only
  )
)

c1 <- Circle$new()
c1$radius <- 7
c1$area           # 153.94
c1$circumference  # 43.98

Inheritance

SavingsAccount <- R6Class("SavingsAccount",
  inherit = BankAccount,
  private = list(rate = 0.06),

  public = list(
    initialize = function(owner, balance, rate=0.06) {
      super$initialize(owner, balance)
      private$rate <- rate
    },
    add_interest = function() {
      interest <- self$get_balance() * private$rate
      self$deposit(interest)
      cat("Interest added: ₹", interest, "\n")
      invisible(self)
    }
  )
)

sav <- SavingsAccount$new("Balu", 20000)
sav$add_interest()
sav$get_balance()   # 21200

Cloning R6 Objects

# R6 objects are references — assignment does NOT copy
acc2 <- acc          # both point to the SAME object!
acc2$deposit(1000)   # modifies acc too!

# To get an independent copy:
acc3 <- acc$clone()
acc3$deposit(500)    # only acc3 is modified

R6 is the right choice when you need objects that maintain state over time — simulation systems, GUI components, database connections, or any object that changes itself through method calls. Its familiar class structure makes it easy to apply if you already know OOP from another language.

Leave a Comment

Your email address will not be published. Required fields are marked *