Dispatch on Two Arguments
Part of the Object Oriented Programming section of Coddy's R journey. Lesson 29 of 57.
An S4 generic can choose its method by the classes of several arguments. The signature lists one class per argument, so each pair of classes can have its own method:
setClass("Asteroid", slots = c(size = "numeric"))
setClass("Ship", slots = c(name = "character"))
invisible(setGeneric("collide", function(a, b) standardGeneric("collide")))
setMethod("collide", signature("Asteroid", "Ship"), function(a, b) paste(b@name, "is hit"))
setMethod("collide", signature("Ship", "Ship"), function(a, b) "two ships bump")
rock <- new("Asteroid", size = 3)
enterprise <- new("Ship", name = "Enterprise")
print(collide(rock, enterprise))
print(collide(enterprise, enterprise))Output:
[1] "Enterprise is hit"
[1] "two ships bump"The class "ANY" matches every class. A method for signature("ANY", "ANY") is the fallback that runs when no more specific pair fits:
setClass("Ship", slots = c(name = "character"))
invisible(setGeneric("collide", function(a, b) standardGeneric("collide")))
setMethod("collide", signature("Ship", "Ship"), function(a, b) "two ships bump")
setMethod("collide", signature("ANY", "ANY"), function(a, b) "nothing happens")
s <- new("Ship", name = "A")
cat(collide(s, s), "/", collide(s, 42), "/", collide("x", "y"))Output:
two ships bump / nothing happens / nothing happensThe order of the arguments matters: signature("A", "B") and signature("B", "A") are different methods. Basic classes such as numeric and character can appear in a signature too:
invisible(setGeneric("join", function(x, y) standardGeneric("join")))
setMethod("join", signature("character", "numeric"), function(x, y) paste(x, "number", y))
setMethod("join", signature("numeric", "character"), function(x, y) paste(y, "after number", x))
print(join("item", 3))
print(join(3, "item"))Output:
[1] "item number 3"
[1] "item after number 3"The class "missing" in a signature matches an argument that was not given at all, so one generic can offer a short and a long form:
invisible(setGeneric("greet", function(name, greeting) standardGeneric("greet")))
setMethod("greet", signature("character", "missing"), function(name, greeting) paste("Hello,", name))
setMethod("greet", signature("character", "character"), function(name, greeting) paste0(greeting, ", ", name))
print(greet("Ada"))
print(greet("Ada", "Good morning"))Output:
[1] "Hello, Ada"
[1] "Good morning, Ada"Challenge
EasyShipping prices depend on the item and the zone. The classes are declared in Item.R (Letter, Box, each with a slot kg) and Zone.R (Domestic, Abroad, each with a slot name). In Rates.R create the generic shipping(item, zone) and one method per pair:
Letterat home: 1; abroad: 3.Boxat home: 5 plus 2 per kg; abroad: 12 plus 4 per kg.- Any other pair: stop with
no rate for this item and zone(usecall. = FALSE).
The supplied code reads lines box home 2.5 (item, zone, kg), where unknown words stay plain text, and prints box to home: 10.00 or error: and the message.
Your code goes in Item.R, Zone.R and Rates.R. main.R holds the supplied input/output code and cannot be edited.
Try it yourself
source("Item.R")
source("Zone.R")
source("Rates.R")
# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
kg <- as.numeric(p[3])
item <- switch(p[1], letter = new("Letter", kg = kg), box = new("Box", kg = kg), kg)
zone <- switch(p[2], home = new("Domestic", name = "home"), abroad = new("Abroad", name = "abroad"), p[2])
out <- tryCatch(sprintf("%s to %s: %.2f", p[1], p[2], shipping(item, zone)),
error = function(e) paste("error:", conditionMessage(e)))
cat(out, "\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 Payroll6S4 Generics and Methods
Creating GenericsMethods for Built-insDispatch on Two ArgumentssetValidity and validObjectRecap - Money and CurrencyPractice on your own: Online R compiler