Extending With NextMethod
Part of the Object Oriented Programming section of Coddy's R journey. Lesson 14 of 57.
A child method often does the parent's work plus a little more. NextMethod() calls the parent method, so the child adds only what is new. A manager's monthly pay is an employee's pay plus the bonus:
pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
pay.manager <- function(x) NextMethod() + x$bonus / 12
m <- structure(list(salary = 60000, bonus = 12000), class = c("manager", "employee"))
e <- structure(list(salary = 36000), class = "employee")
cat(pay(e), pay(m))Output:
3000 6000NextMethod() keeps working down several levels. Each method adds its part and hands on to the class after its own:
pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
pay.manager <- function(x) NextMethod() + x$bonus / 12
pay.director <- function(x) NextMethod() + 500
d <- structure(list(salary = 120000, bonus = 24000),
class = c("director", "manager", "employee"))
print(pay(d))Output:
[1] 12500A child method can also check first and hand on only when the check passes. The parent's method returns the changed object with its full class vector, so the result is still a savings account:
withdraw <- function(acc, amount) UseMethod("withdraw")
withdraw.account <- function(acc, amount) {
if (amount > acc$balance) stop("insufficient funds", call. = FALSE)
acc$balance <- acc$balance - amount
acc
}
withdraw.savings <- function(acc, amount) {
if (amount > 500) stop("savings limit is 500", call. = FALSE)
NextMethod()
}
s <- structure(list(balance = 1000), class = c("savings", "account"))
s <- withdraw(s, 200)
cat(s$balance, class(s))Output:
800 savings accountConstructors and methods reuse the parent in the same way: new_manager() calls new_employee(), and pay.manager() calls NextMethod(). The employee code is written once and every subclass builds on it:
new_manager <- function(name, salary, bonus) {
new_employee(name, salary, bonus = bonus, class = "manager") # reuse the constructor
}
pay.manager <- function(x) NextMethod() + x$bonus / 12 # reuse the methodChallenge
EasyAccounts and savings accounts are in two files. In Account.R complete withdraw.account(acc, amount), which stops with insufficient funds when the amount is above the balance and otherwise returns the account with the lower balance, and format.account(), which returns ada: 800. In Savings.R complete withdraw.savings(), which stops with savings limit is 500 for amounts above 500 and otherwise hands on with NextMethod(), and format.savings(), which returns ada: 800 (savings) by calling NextMethod().
Use call. = FALSE. The generic and constructors are given. The supplied code reads savings ada 1000 or account bo 300, then amounts to withdraw; it prints withdrew 200 or refused: and the message, and finally the formatted account.
Your code goes in Account.R and Savings.R. main.R holds the supplied input/output code and cannot be edited.
Try it yourself
source("Account.R")
source("Savings.R")
# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], " ")[[1]]
acc <- if (p[1] == "savings") new_savings(p[2], as.numeric(p[3])) else new_account(p[2], as.numeric(p[3]))
for (amount in as.numeric(input[-1])) {
acc <- tryCatch({
acc <- withdraw(acc, amount)
cat("withdrew ", amount, "\n", sep = "")
acc
}, error = function(e) {
cat("refused: ", conditionMessage(e), "\n", sep = "")
acc
})
}
cat(format(acc), "\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 Books3S3 Inheritance
Class VectorsMethod Lookup OrderExtending With NextMethodChecking With inherits()Recap - Staff PayrollPractice on your own: Online R compiler