Menu
Coddy logo textTech

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 icon

Challenge

Easy

Tasks 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 = "")
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Online R compiler