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)