๐ŸŽ“ A1Learner
๐Ÿ”
0 of 27 lessons completed

R S4 Inheritance

S4 inheritance lets a new class build on a class that already exists. The new class keeps the parent slots and adds slots of its own.

A subclass adds a slot

Savings builds on Wallet with contains =. The new object fills two inherited slots and its own rate slot.

setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Savings", contains = "Wallet", slots = c(rate = "numeric"), prototype = list(rate = 2))
s <- new("Savings", balance = 40, owner = "Bo", rate = 3)
print(s@balance)
print(s@owner)
print(s@rate)

The full slot dump

print() shows the rate slot and both inherited slots. slotNames() lists all three names together.

setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Savings", contains = "Wallet", slots = c(rate = "numeric"), prototype = list(rate = 2))
s <- new("Savings", balance = 40, owner = "Bo", rate = 3)
print(s)
print(slotNames(s))

A parent method runs for a subclass

describe is written for Wallet. The same method runs for a Savings object and reads its inherited slots.

setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Savings", contains = "Wallet", slots = c(rate = "numeric"), prototype = list(rate = 2))
g <- setGeneric("describe", function(x) standardGeneric("describe"))
setMethod("describe", "Wallet", function(x) cat(x@owner, "has", x@balance, "coins\n"))
s <- new("Savings", balance = 40, owner = "Bo", rate = 3)
describe(s)
w <- new("Wallet", balance = 7, owner = "Cy")
describe(w)

is checks the parent class

is() reports TRUE for both the subclass and the parent class. A plain Wallet object is not a Savings object.

setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Savings", contains = "Wallet", slots = c(rate = "numeric"), prototype = list(rate = 2))
s <- new("Savings", balance = 40, owner = "Bo", rate = 3)
print(is(s, "Savings"))
print(is(s, "Wallet"))
w <- new("Wallet", balance = 7, owner = "Cy")
print(is(w, "Savings"))

Example

setClass("Wallet", slots = c(balance = "numeric", owner = "character"), prototype = list(balance = 0, owner = "Ana"))
setClass("Savings", contains = "Wallet", slots = c(rate = "numeric"), prototype = list(rate = 2))
g <- setGeneric("describe", function(x) standardGeneric("describe"))
setMethod("describe", "Wallet", function(x) cat(x@owner, "has", x@balance, "coins\n"))
s <- new("Savings", balance = 60, owner = "Ana", rate = 5)
print(is(s, "Wallet"))
describe(s)
print(s@rate)

Key points

  • contains = inside setClass() names the parent class.
  • The subclass holds the parent slots alongside its own slots.
  • new() fills the inherited slots and the new slots in one call.
  • An object reads an inherited slot with @ in the same way as its own slot.
  • is() returns TRUE when an object is checked against its parent class.
  • A method written for the parent class also runs for the subclass.

In this example, Savings builds on Wallet and holds a balance of 60 with a rate of 5. is() confirms the object is also a Wallet, and the Wallet method describes it through its inherited slots.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท rdrr.io R Snippets

Exercise

What does contains = "Wallet" do inside a setClass() call for Savings?