Chapter 16 Trade-Offs
Can we make a class using S3
, S4
, and R6
so we can easily directly compare the three, and their generics and methods?
16.0.1 Using our example from the S4 Chapter:
setClass("Person",
slots = c(
name = "character",
age = "numeric"
)
)
setGeneric("age", function(x) standardGeneric("age"))
setGeneric("age<-", function(x, value) standardGeneric("age<-"))
setMethod("age", "Person", function(x) x@age)
setMethod("age<-", "Person", function(x, value) {
x@age <- value
x
})
john <- new("Person", name = "John Smith", age = 12)
age(john)
[1] 12
A generic is a function that will dispatch differently based on the class it is applied to. Above we apply the age
generic to Person
using setMethod
but we could create an age
method that behaves differently for another class, like dogs (which will add 7 to the supplied age)
setClass("Person", slots = c(name = "character",age = "numeric"))
setGeneric("age", function(x) standardGeneric("age"))
setGeneric("age<-", function(x, value) standardGeneric("age<-"))
setMethod("age", "Person", function(x) x@age)
setMethod("age<-", "Person", function(x, value) {
x@age <- value
x
})
setClass("Dog", slots = c(name = "character", age = "numeric"))
# You want the age generic to automatically return 7x the slot in human years
setMethod("age", "Dog", function(x) {x@age*7} )
setMethod("age<-", "Dog", function(x, value) {
x@age <- value
x
})
spot <- new("Dog", name = "Spot Smith", age = 12)
age(spot)
We can do this with S3:
johnny <- structure(
list(name = "Johnny Smith",
age = 12),
class = "s3_human")
stripe <- structure(
list(name = "Stripe Smith",
age = 12),
class = "s3_dog")
s3_age <- function(x){UseMethod("s3_age")}
s3_age.s3_dog <- function(x){x$age*7}
s3_age.s3_human <- function(x){x$age}
s3_age(johnny)
## [1] 12
## [1] 84
And R6
Person <- R6Class("Person", list(
name = NULL,
age = NULL,
initialize = function(name, age = NA) {
stopifnot(is.character(name), length(name) == 1)
stopifnot(is.numeric(age), length(age) == 1)
self$name <- name
self$age <- age
}
))
john <- Person$new(name = "John Smith", age = 12)
john$age
[1] 12
Dog <- R6Class(
"Dog",
inherit = Person,
public = list(
initialize = function(name, age = NA) {
super$initialize(name,age)
self$age <- age * 7
}
))
spot <- Dog$new(name = "Spot Smith", age = 12)
spot$age
[1] 84