R S4 Generics
An S4 generic is a function that picks a method by the class of its argument. setGeneric creates the generic and setMethod adds a method for one class.
A generic with one method
describe is the generic and the Wallet method prints one line about the wallet. The call on a Wallet object runs that method.
setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
g <- setGeneric("describe", function(object) {
standardGeneric("describe")
})
setMethod("describe", "Wallet", function(object) {
cat(paste0("Wallet for ", object@owner, " holds ", object@balance, "\n"))
})
w <- new("Wallet", balance = 40, owner = "Bo")
describe(w)Two classes, two methods
Voucher is a second class with its own describe method. The same call runs the Wallet method for the wallet and the Voucher method for the voucher.
setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Voucher", slots = c(code = "character", value = "numeric"), prototype = list(code = "GIFT", value = 10))
g <- setGeneric("describe", function(object) {
standardGeneric("describe")
})
setMethod("describe", "Wallet", function(object) {
cat(paste0("Wallet for ", object@owner, " holds ", object@balance, "\n"))
})
setMethod("describe", "Voucher", function(object) {
cat(paste0("Voucher ", object@code, " is worth ", object@value, "\n"))
})
w <- new("Wallet", balance = 40, owner = "Bo")
v <- new("Voucher", code = "SAVE", value = 15)
describe(w)
describe(v)Dispatch from a list of objects
Both objects sit in one list and each one is passed to describe in turn. Each call picks the method for the class of the object it receives.
setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Voucher", slots = c(code = "character", value = "numeric"), prototype = list(code = "GIFT", value = 10))
g <- setGeneric("describe", function(object) {
standardGeneric("describe")
})
setMethod("describe", "Wallet", function(object) {
cat(paste0("Wallet for ", object@owner, " holds ", object@balance, "\n"))
})
setMethod("describe", "Voucher", function(object) {
cat(paste0("Voucher ", object@code, " is worth ", object@value, "\n"))
})
items <- list(new("Wallet", balance = 25, owner = "Cy"), new("Voucher", code = "PLUS", value = 20))
describe(items[[1]])
describe(items[[2]])Example
setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Voucher", slots = c(code = "character", value = "numeric"), prototype = list(code = "GIFT", value = 10))
g <- setGeneric("describe", function(object) {
standardGeneric("describe")
})
setMethod("describe", "Wallet", function(object) {
cat(paste0("Wallet for ", object@owner, " holds ", object@balance, "\n"))
})
setMethod("describe", "Voucher", function(object) {
cat(paste0("Voucher ", object@code, " is worth ", object@value, "\n"))
})
w <- new("Wallet", balance = 60, owner = "Dee")
v <- new("Voucher")
describe(v)
describe(w)
print(w@balance)Key points
- setGeneric takes a name and a function whose body calls standardGeneric.
- standardGeneric hands the call to the method that matches the class of the argument.
- setMethod takes the generic name, a class name and the method function.
- The method function receives the object the generic was called with.
- The same generic call runs different methods for different classes.
- setGeneric returns the generic name, so the call is assigned to a variable to keep the output clean.
In this example, the voucher uses its prototype code and value, so its method prints the GIFT line first. The wallet call then runs the Wallet method and the last print reads the balance slot as 60.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท rdrr.io R Snippets
Exercise
What does setMethod add to an S4 generic?