Menu
Coddy logo textTech

Copy Semantics

Part of the Object Oriented Programming section of Coddy's R journey. Lesson 39 of 57.

S3 and S4 objects are values: a function that changes one changes its own copy. RC objects are references: the caller's object changes. The same function behaves differently for the two kinds:

setClass("S4Box", slots = c(n = "numeric"))
RCBox <- setRefClass("RCBox", fields = list(n = "numeric"))
bump_s4 <- function(b) { b@n <- b@n + 1; invisible(b) }
bump_rc <- function(b) b$n <- b$n + 1
v <- new("S4Box", n = 1)
r <- RCBox$new(n = 1)
bump_s4(v)
bump_rc(r)
cat(v@n, r$n)

Output:

1 2

$copy() creates a new, independent object with the same field values. Changing the copy leaves the original alone:

Account <- setRefClass("Account", fields = list(balance = "numeric"))
a <- Account$new(balance = 100)
alias <- a
backup <- a$copy()
alias$balance <- 0
cat(a$balance, backup$balance)

Output:

0 100

A list can hold the same RC object several times. Changing one element then changes all of them. Create a new object per element when they must be independent:

Counter <- setRefClass("Counter", fields = list(n = "numeric"))
one <- Counter$new(n = 0)
same <- list(one, one, one)
same[[1]]$n <- 5
fresh <- lapply(1:3, function(i) Counter$new(n = 0))
fresh[[1]]$n <- 5
cat(same[[3]]$n, fresh[[3]]$n)

Output:

5 0

identical(a, b) is TRUE for two names of the same RC object, and FALSE for a copy, even while the fields are still equal:

Account <- setRefClass("Account", fields = list(balance = "numeric"))
a <- Account$new(balance = 100)
b <- a
c2 <- a$copy()
cat(identical(a, b), identical(a, c2), c2$balance == a$balance)

Output:

TRUE FALSE TRUE
challenge icon

Challenge

Easy

A text editor keeps save points. Declare the Reference Class Document in Document.R with the field text (character) and a method type(s) that appends s to the text. Then write checkpoint(doc), which returns an independent copy of the document.

The definition with methods is wrapped in suppressMessages(). The supplied code starts with a save point, then reads commands: save stores checkpoint(doc), undo goes back to a copy of the last save point, and any other line is typed. It prints the text and the saved text after each command, so a save point must never change when typing continues.

Your code goes in Document.R. main.R holds the supplied input/output code and cannot be edited.

Try it yourself

source("Document.R")

# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
doc <- Document$new(text = "")
saved <- checkpoint(doc)
for (cmd in input) {
  if (cmd == "save") {
    saved <- checkpoint(doc)
  } else if (cmd == "undo") {
    doc <- checkpoint(saved)
  } else {
    doc$type(cmd)
  }
  cat(cmd, " -> [", doc$text, "] saved [", saved$text, "]\n", sep = "")
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Online R compiler