Method Lookup Order
Part of the Object Oriented Programming section of Coddy's R journey. Lesson 13 of 57.
For every call, R walks the class vector from left to right and runs the first method it finds. If no class has a method, it uses the default. Different objects in one hierarchy can stop at different levels:
move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.default <- function(x) "stays"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
dog <- structure(list(), class = c("dog", "animal"))
rock <- structure(list(), class = "rock")
cat(move(penguin), move(dog), move(rock))Output:
flies walks staysA child overrides a parent method by defining its own. The override affects only the child and anything below it; the parent and its other children keep the parent method:
move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.penguin <- function(x) "swims"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
sparrow <- structure(list(), class = c("bird", "animal"))
cat(move(penguin), move(sparrow))Output:
swims fliesEach generic is looked up on its own. One object can take sound() from its own class and move() from a parent, and a parent method can call other generics that dispatch on the child again:
sound <- function(x) UseMethod("sound")
move <- function(x) UseMethod("move")
describe <- function(x) UseMethod("describe")
sound.animal <- function(x) "..."
sound.dog <- function(x) "woof"
move.animal <- function(x) "walks"
describe.animal <- function(x) paste(x$name, "says", sound(x), "and", move(x))
rex <- structure(list(name = "Rex"), class = c("dog", "animal"))
print(describe(rex))Output:
[1] "Rex says woof and walks"For an object with a class attribute, dispatch looks only at that attribute and then the default. The object is still a list inside, but a method for list is not tried:
size <- function(x) UseMethod("size")
size.list <- function(x) "a list"
size.default <- function(x) "default"
bag <- structure(list(1, 2), class = "bag")
cat(size(list(1, 2)), "/", size(bag))Output:
a list / defaultChallenge
EasyA square is a rectangle with equal sides. In Rectangle.R write the methods area.rectangle(), perimeter.rectangle() and name.rectangle(), which returns rectangle 2x3. In Square.R complete new_square(side), which calls new_rectangle() with the class square, and override only name() with name.square(), which returns square 2. Squares must use the rectangle's area() and perimeter().
The generics and new_rectangle() are given. The supplied code reads lines with two numbers (a rectangle) or one (a square) and prints square 2: area 4, perimeter 8.
Your code goes in Rectangle.R and Square.R. main.R holds the supplied input/output code and cannot be edited.
Try it yourself
source("Rectangle.R")
source("Square.R")
# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
n <- as.numeric(strsplit(line, " ")[[1]])
s <- if (length(n) == 1) new_square(n[1]) else new_rectangle(n[1], n[2])
cat(name(s), ": area ", area(s), ", perimeter ", perimeter(s), "\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