NextMethod Basics
Part of the Object Oriented Programming section of Coddy's R journey. Lesson 10 of 57.
Inside a method, NextMethod() calls the next method in line for the same generic, with the same arguments. For an object with one class, the next method is the default one, so a method can reuse the general answer and add to it:
describe <- function(x) UseMethod("describe")
describe.default <- function(x) paste("an object with", length(x), "fields")
describe.task <- function(x) paste0(NextMethod(), ", titled ", x$title)
t <- structure(list(title = "Buy milk", done = FALSE), class = "task")
print(describe(t))Output:
[1] "an object with 2 fields, titled Buy milk"An object can have several classes in a vector, such as c("urgent", "task"). Dispatch tries them in order, and NextMethod() in the first method moves on to the method for the next class:
describe <- function(x) UseMethod("describe")
describe.task <- function(x) paste("task:", x$title)
describe.urgent <- function(x) paste("URGENT", NextMethod())
fix <- structure(list(title = "Fix the leak"), class = c("urgent", "task"))
print(describe(fix))Output:
[1] "URGENT task: Fix the leak"NextMethod() passes on every argument the method received, including extra ones such as sep. The next method sees the same values without you listing them again:
label <- function(x, sep = ": ") UseMethod("label")
label.default <- function(x, sep = ": ") paste0("item", sep, x$name)
label.box <- function(x, sep = ": ") paste0("[", NextMethod(), "]")
b <- structure(list(name = "tools"), class = "box")
print(label(b))
print(label(b, sep = " = "))Output:
[1] "[item: tools]"
[1] "[item = tools]"Base R uses NextMethod() to keep a class when a vector is subset. The default [ drops the class, so a "[.percent" method lets it do the work and puts the class back:
format.percent <- function(x, ...) paste0(unclass(x) * 100, "%")
"[.percent" <- function(x, i) structure(NextMethod(), class = "percent")
p <- structure(c(0.1, 0.25, 0.5), class = "percent")
print(format(p[2:3]))Output:
[1] "25%" "50%"Challenge
EasyTasks and urgent tasks are two classes in two files. In Task.R complete the generic describe(), the default method, which returns an item, and describe.task(), which returns an item: Buy milk by calling NextMethod() and adding the title. In Urgent.R complete describe.urgent(), which returns URGENT an item: Fix bug by calling NextMethod().
The constructors are given: an urgent task has the class c("urgent", "task"). The supplied code reads lines task Buy milk, urgent Fix bug or any other word with a title, which becomes an object of that class, and prints describe() for each.
Your code goes in Task.R and Urgent.R. main.R holds the supplied input/output code and cannot be edited.
Try it yourself
source("Task.R")
source("Urgent.R")
# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
kind <- sub(" .*", "", line)
title <- sub("^[a-z]+ ", "", line)
t <- if (kind == "urgent") new_urgent(title) else if (kind == "task") new_task(title) else structure(list(title = title), class = kind)
cat(describe(t), "\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 BooksPractice on your own: Online R compiler