Accessor Functions
Part of the Object Oriented Programming section of Coddy's R journey. Lesson 19 of 57.
Encapsulation means other code works with an object through functions instead of reaching into its fields. A getter reads a value and a setter changes it. For an S3 list, the setter returns the changed copy:
new_member <- function(name) structure(list(name = name), class = "member")
get_name <- function(p) p$name
set_name <- function(p, value) {
p$name <- value
p
}
p <- new_member("ada")
p <- set_name(p, "Ada Lovelace")
print(get_name(p))Output:
[1] "Ada Lovelace"Accessors let the object change how it stores data without breaking the code that uses it. This thermometer stores Celsius, and a getter works out Fahrenheit when asked, so callers never see the field itself:
new_thermo <- function(c) structure(list(c = c), class = "thermo")
celsius <- function(t) t$c
fahrenheit <- function(t) t$c * 9 / 5 + 32
t <- new_thermo(25)
cat(celsius(t), fahrenheit(t))Output:
25 77R's own setters, such as names(x) <- ..., are replacement functions. A function named "name<-" with the parameters x and value lets callers write name(p) <- "Bo"; R calls it and assigns the result back to p:
new_member <- function(name) structure(list(name = name), class = "member")
name <- function(p) p$name
"name<-" <- function(x, value) {
x$name <- trimws(value)
x
}
p <- new_member("ada")
name(p) <- " Bo "
print(name(p))Output:
[1] "Bo"A getter of a closure object returns a copy of the private data. Changing that copy does not change the object, so the only way in is through the object's own functions:
make_list <- function() {
items <- character(0)
list(add = function(x) items <<- c(items, x),
get_items = function() items)
}
todo <- make_list()
todo$add("milk")
mine <- todo$get_items()
mine[1] <- "HACKED"
print(todo$get_items())Output:
[1] "milk"Challenge
EasyA contact is an S3 list of class contact with the fields name and email. Complete Contact.R:
new_contact(name, email)stores the email trimmed and in lower case.- The getters
contact_name(x)andcontact_email(x). - The replacement function
"contact_email<-", which stores the new email trimmed and in lower case, so callers can writecontact_email(c1) <- value.
The supplied code reads name,email, then new emails, and prints Ada <ada@x.com> after each change and the stored field names at the end.
Your code goes in Contact.R. main.R holds the supplied input/output code and cannot be edited.
Try it yourself
source("Contact.R")
# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], ",")[[1]]
c1 <- new_contact(p[1], p[2])
cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
for (value in input[-1]) {
contact_email(c1) <- value
cat(contact_name(c1), " <", contact_email(c1), ">\n", sep = "")
}
cat("stored fields: ", paste(names(unclass(c1)), collapse = ", "), "\n", sep = "")
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1S3 Basics
Working With FilesLists With a ClassConstructor FunctionsPrint and Format MethodsValidators and HelpersRecap - Temperatures4Encapsulation in R
Closures as ObjectsEnvironments as ObjectsAccessor FunctionsGuarding StateRecap - Parking Meter2S3 Generics and Methods
Generics and UseMethodDefault MethodsMethods for Base GenericsNextMethod BasicsRecap - Shape Areas8Reference Classes
Defining Reference ClassesMethods and Field UpdatesCopy SemanticsInheritance and callSuperRecap - Task Queue11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Online R compiler