The inner workings of `NextMethod()`
Consider this example where generic function f
is called and it invokes f.ordered
and then, using NextMethod
, f.ordered
invokes f.factor
:
f <- function(x) UseMethod("f") # generic
f.ordered <- function(x) { x <- x[-1]; NextMethod() }
f.factor <- function(x) x # inherited method
x <- ordered(c("a", "b", "c"))
class(x)
## [1] "ordered" "factor"
f(x)
## [1] b c
## Levels: a < b < c
Now consider the original text:
Turning now to methods invoked as a result of a call to NextMethod(), these behave as if they had been called from the previous method with a special call.
Here f
calls f.ordered
which calls f.factor
so the method "invoked as a
result of a call to NextMethod" is f.factor
and the previous method is
f.ordered
.
The arguments in the call to the inherited method are the same in number, order, and actual argument names as those in the call to the current method (and, therefore, in the call to the generic). The expressions for the arguments, however, are the names of the corresponding formal arguments of the current method. Suppose, for example, that the expression print(ratings) has invoked the method print.ordered(). When this method invokes NextMethod(), this is equivalent to a call to print.factor() of the form print.factor(x), where x is here the x in the frame of print.ordered()
Now we switch perspectives and we are sitting in f.ordered
so now f.ordered
is the current method and f.factor
is the inherited method.
At the point that f.ordered
invokes NextMethod()
a special call is constructed
to call f.factor
whose arguments are the same as those passed to f.ordered
and
to the generic f
except that they refer to the versions of the arguments in f.ordered
(which
makes a difference here as f.ordered
changes the argument before invoking
f.factor
.
Hard to go through all this post, but I think that this small example can help to demystify the NextMethod
dispatching.
I create an object with 2 classes attributes (inheritance) 'first' and 'second'.
x <- 1
attr(x,'class') <- c('first','second')
Then I create a generic
method Cat
to print my object
Cate <- function(x,...)UseMethod('Cate')
I define Cate
method for each class.
Cate.first <- function(x,...){
print(match.call())
print(paste('first:',x))
print('---------------------')
NextMethod() ## This will call Cate.second
}
Cate.second <- function(x,y){
print(match.call())
print(paste('second:',x,y))
}
Now you can can check Cate
call using this example:
Cate(x,1:3)
Cate.first(x = x, 1:3)
[1] "first: 1"
[1] "---------------------"
Cate.second(x = x, y = 1:3)
[1] "second: 1 1" "second: 1 2" "second: 1 3"
- For Cate.second the previous method is Cate.first
- Arguments x and y are passed down from the current method to the inherited method with their current values at the time NextMethod() is called.
- Argument y passed through the "..." formal argument arrive with the correct argument name
Cate.second(x = x, y = 1:3)