R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
124: R6 Classes for Reference Semantics
Think about the difference between sending someone a Word document via email and sharing a Google Doc with them. If I email you a .docx file, you have your own copy. You can delete paragraphs, change the font to Comic Sans, or rewrite the ending, and my original file remains untouched. If you want me to see those changes, you have to send the whole file back to me, and I have to overwrite my version with yours. That's how almost everything in R works—it's called "value semantics" or "copy-on-modify."
Now, imagine a shared Google Doc. We both have a link to the exact same document. If you change a sentence, I see it happen in real-time. We aren't passing copies back and forth; we are both referencing the same object in memory. This is "reference semantics," and in R, the R6 package is our primary tool for achieving this.
Moving Beyond the Copy-on-Modify Headache
In standard R (S3 or S4), if you have a large object and you want to change one small piece of it inside a function, R often creates a copy of that entire object. When your data grows to millions of rows, this becomes a performance nightmare. Even for small objects, the syntax gets clunky: you're constantly doing my_obj <- update_function(my_obj).
With R6, we stop doing that. We create an object that stays put in memory, and we tell R to go to that specific address and change a value. I find this indispensable when I'm building complex systems—like a database connection manager or a simulation engine—where I need a single "source of truth" that different parts of my program can update simultaneously.
Building a State-Aware Bank Account
Let's look at how this actually looks in code. We'll build a simple bank account. In a traditional R function, adding money would require returning a new version of the account. Here, we just update the internal state.
library(R6)
BankAccount <- R6Class("BankAccount",
public = list(
owner = NULL,
balance = 0,
initialize = function(owner, initial_deposit) {
self$owner <- owner
self$balance <- initial_deposit
},
deposit = function(amount) {
self$balance <- self$balance + amount
invisible(self) # Returning 'self' allows for method chaining
},
withdraw = function(amount) {
if (amount > self$balance) {
stop("Insufficient funds!")
}
self$balance <- self$balance - amount
invisible(self)
}
)
)
# Let's create an account
my_account <- BankAccount$new("Alice", 100)
Notice the self$ syntax. In R6, self is the equivalent of this in Java or Python. It tells R, "I'm talking about the field belonging to this specific instance of the class."
Proving the Reference
This is the part where the "Google Doc" analogy really clicks. Watch what happens when we assign our account to a second variable. In standard R, this would create a copy. In R6, it just creates another pointer to the same object.
# Create a second reference to the same account
bob_reference <- my_account
# Bob deposits money into his reference
bob_reference$deposit(50)
# Check Alice's account balance
print(my_account$balance)
# Output: 150
Alice's balance changed even though we called the method on bob_reference. Why? Because my_account and bob_reference are just two different names for the same piece of memory. I've seen a lot of developers get tripped up by this when they expect a copy, so be careful: if you actually want a separate copy of an R6 object, you have to explicitly call my_account$clone().
📋 Practical Task
Implementing a Persistent Portfolio Tracker
Your task is to create an R6 class called PortfolioTracker that manages a collection of stock symbols and their quantities. Unlike a simple list, this tracker needs to maintain its state across different variables.
Requirements:
- The class should have a public field called
holdings, initialized as an empty named list. - Implement a method
add_stock(symbol, quantity). If the symbol already exists inholdings, add the quantity to the existing amount. If it doesn't exist, create a new entry. - Implement a method
get_total_shares()that returns the sum of all quantities in the portfolio. - Demonstrate reference semantics: Create one portfolio object, assign it to a second variable, use the second variable to add stocks, and then print the
holdingsof the first variable to prove they are the same object.
There are no comments for now.