15.5 Method Chaining
In this Section we will explore a concise and convenient device for calling multiple methods on an object. The device is known as method chaining.
In order to illustrate method chaining, we’ll extend the class Lion a bit, with some new attributes and new methods. First of all, we’d like to add a data frame consisting of possible animals on which a lion might prey. The data frame will contain the name of each type of animal, and an associated weight.
<- c(
animal "zebra", "giraffe", "pig",
"cape buffalo", "antelope", "wildebeast"
)<- c(50, 100, 25, 60, 45, 55)
mass <- data.frame(animal, mass, stringsAsFactors = FALSE) prey
Let’s now add prey
as a new attribute to class Lion. We will also add an attribute eaten
: a character vector—initially empty—that will contain a record of all the animals that the lion has eaten.
$set("public", "prey", prey, overwrite = TRUE)
Lion$set("public", "eaten", character(), overwrite = TRUE) Lion
Let us now endow our lions with the capacity to eat a beast of prey, by adding the method eat()
:
$set("public", "eat", function() {
Lion<- nrow(self$prey)
n <- self$prey[sample(1:n, size = 1), ]
item <- substr(item$animal, 1, 1)
initLetter <- ifelse(initLetter %in% c("a", "e", "i", "o", "u"), "An ", "A ")
article cat(article, item$animal, " was eaten just now ...\n\n", sep = "")
$eaten <- c(self$eaten, item$animal)
self$weight <- self$weight + item$mass
selfreturn(invisible(self))
overwrite = TRUE) },
When it eats an animal—randomly selected from the prey
data frame—the lion gains the amount of weight that is associated with its unfortunate victim, and the victim is added to the lion’s eaten
attribute.
Note that the eat()
method returns self
invisibly. When the method is called on a lion, that very lion itself is returned as a value, but since it is returned invisibly it won’t be printed to the console. The usefulness of returning self
will soon become apparent.
Lions enjoy talking about what they have eaten recently, and for some reason they monitor their weight obsessively. The new method report()
accounts for these characteristics of lions:
$set("public", "report", function() {
Lion<- length(self$eaten)
n if (n >= 1) {
cat("My name is ", self$name, ".\n", sep = "")
cat("My most recent meal consisted of: ", self$eaten[n], ".\n", sep = "")
}cat("I now weigh ", self$weight, " pounds.\n", sep = "")
return(invisible(self))
overwrite = TRUE) },
Note that report()
also returns the lion invisibly.
Let us now instantiate a new lion named Simba:
<- Lion$new(
simba name = "Simba", age = 10,
desire = "Hakuna Matata"
)
## Grr! My name is Simba!
$set_weight(300) simba
## Simba has weight: 300.
Having been created after the addition of the prey
and eaten
attributes and the eat()
and report()
methods, simba
has access to all of them. in particular, he can eat a random beast of prey:
$eat() simba
## A cape buffalo was eaten just now ...
simba
has eaten, and he has presumably gained some weight as a result. Let’s see verify this by asking for his report:
$report() simba
## My name is Simba.
## My most recent meal consisted of: cape buffalo.
## I now weigh 360 pounds.
Let’s now have simba
eat twice more, and then report. Because eat()
and report()
both return simba
, we can
- call
eat()
on `simba, - and then immediately call
eat()
on the result, - and finally call
report()
on the result of our second call.
All of this can be accomplished in one line of calls, in which the three method-calls are “chained” together with dollar-signs:
$eat()$eat()$report() simba
## A pig was eaten just now ...
##
## A cape buffalo was eaten just now ...
##
## My name is Simba.
## My most recent meal consisted of: cape buffalo.
## I now weigh 445 pounds.
In object-oriented programming languages you will see method-chaining used quite frequently.