The R Project SVN R

Rev

Rev 88267 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

% File src/library/methods/man/NextMethod.Rd
% Part of the R package, https://www.R-project.org
% Copyright 1995-2017 R Core Team
% Distributed under GPL 2 or later

\name{callNextMethod}
\alias{callNextMethod}
\title{Call an Inherited Method}
\description{
  A call to \code{callNextMethod} can only appear inside a method
  definition.  It then results in a call to the first inherited method
  after the current method, with the arguments to the current method
  passed down to the next method.  The value of that method call is the
  value of \code{callNextMethod}.
}
\usage{
callNextMethod(...)
}
\arguments{
  \item{\dots}{
    Optionally, the arguments to the function in its next call
    (but note that the dispatch is as in the detailed description below;
    the arguments have no effect on selecting the next method.)

    If no arguments are included in the call to \code{callNextMethod}, the
    effect is to call the method with the current arguments.
    See the detailed description for what this really means.

    Calling with no arguments is often the natural way to use
    \code{callNextMethod}; see the examples.
    }
}
\details{
  The \sQuote{next} method (i.e., the first inherited method) is defined
  to be that method which \emph{would} have been called if the current
  method did not exist. This is more-or-less literally what happens: The
  current method (to be precise, the method with signature given by the
  \code{defined} slot of the method from which \code{callNextMethod} is
  called) is deleted from a copy of the methods for the current generic,
  and \code{\link{selectMethod}} is called to find the next method (the
  result is cached in the method object where the call occurred, so the search typically
  happens only once per session per combination of argument classes).

  The next method is defined from the \emph{signature} of the current
  method, not from the actual classes of the arguments.
  In particular, modifying any of the arguments has no effect on the
  selection.
  As a result, the selected next method can be called with invalid
  arguments if the calling function assigns objects of a different
  class before the \code{callNextMethod()} call.
  Be careful of any assignments to such arguments.

  It is possible for the selection of the next method to be ambiguous,
  even though the original set of methods was consistent.
  See the section \dQuote{Ambiguous Selection}.

  The statement that the method is called with the current arguments is
  more precisely as follows.  Arguments that were missing in the current
  call are still missing (remember that \code{"missing"} is a valid
  class in a method signature).  For a formal argument, say \code{x}, that
  appears in the original call, there is a corresponding argument in the
  next method call equivalent to \code{x = x}.  In effect, this
  means that the next method sees the same actual arguments, but
  arguments are evaluated only once.
}
\section{Ambiguous Selection}{
There are two fairly common situations in which the choice of a next
method is ambiguous, even when the original set of methods uniquely
defines all method selection unambiguously.
In these situations, \code{callNextMethod()} should be replaced,
either by a call to a specific function or by recalling the generic
with different arguments.

The most likely situation arises with methods for binary operators,
typically through one of the group generic functions.
See the example for class \code{"rnum"} below.
Examples of this sort usually require three methods: two for the case
that the first or the second argument comes from the class, and a
third for the case that both arguments come from the class.
If that last method uses \code{callNextMethod}, the other two methods
are equally valid.  The ambiguity is exactly the same that required
defining the two-argument method in the first place.

In fact, the two possibilities are equally valid conceptually as well
as formally.
As in the example below, the logic of the application usually requires
selecting a computation explicitly or else calling the generic
function with modified arguments to select an appropriate method.

The other likely source of ambiguity arises from a class that inherits
directly from more than one other class (a \dQuote{mixin} in standard
terminology).
If the generic has methods corresponding to both superclasses, a
method for the current class is again needed to resolve ambiguity.
Using \code{callNextMethod} will again reimpose the ambiguity.
Again, some explicit choice has to be made in the calling method
instead.

These ambiguities are not the result of bad design, but they do
require workarounds.
Other ambiguities usually reflect inconsistencies in the tree of
inheritances, such as a class appearing in more than one place among
the superclasses.
Such cases should be rare, but with the independent definition of
classes in multiple packages, they can't be ruled out.

}
\value{
  The value returned by the selected method.
}
\references{
   \bibshow{R:Chambers:2016}
  (Chapters 9 and 10.)
}
\seealso{\code{\link{callGeneric}} to call the generic function with the
 current dispatch rules (typically for a group generic function);
 \link{Methods_Details} for the general behavior of method dispatch.
}

\examples{
## callNextMethod() used for the Math, Math2 group generic functions

## A class to automatically round numeric results to "d" digits

rnum <- setClass("rnum", slots = c(d = "integer"), contains = "numeric")

## Math functions operate on the rounded numbers, return a plain
## vector.  The next method will always be the default, usually a primitive.
setMethod("Math", "rnum",
          function(x)
              callNextMethod(round(as.numeric(x), x@d)))
setMethod("Math2", "rnum",
          function(x, digits)
              callNextMethod(round(as.numeric(x), x@d), digits))

## Examples of callNextMethod with two arguments in the signature.

## For arithmetic and one rnum with anything, callNextMethod with no arguments
## round the full accuracy result, and return as plain vector
setMethod("Arith", c(e1 ="rnum"),
          function(e1, e2)
              as.numeric(round(callNextMethod(), e1@d)))
setMethod("Arith", c(e2 ="rnum"),
          function(e1, e2)
              as.numeric(round(callNextMethod(), e2@d)))

## A method for BOTH arguments from "rnum" would be ambiguous
## for callNextMethod(): the two methods above are equally valid.
## The method chooses the smaller number of digits,
## and then calls the generic function, postponing the method selection
## until it's not ambiguous.
setMethod("Arith", c(e1 ="rnum", e2 = "rnum"),
          function(e1, e2) {
              if(e1@d <= e2@d)
                  callGeneric(e1, as.numeric(e2))
              else
                  callGeneric(as.numeric(e1), e2)
          })

## For comparisons, callNextMethod with the rounded arguments
setMethod("Compare", c(e1 = "rnum"),
          function(e1, e2)
              callNextMethod(round(e1, e1@d), round(e2, e1@d)))
setMethod("Compare", c(e2 = "rnum"),
          function(e1, e2)
              callNextMethod(round(e1, e2@d), round(e2, e2@d)))

## similarly to the Arith case, the method for two "rnum" objects
## can not unambiguously use callNextMethod().  Instead, we rely on
## The rnum() method inherited from Math2 to return plain vectors.
setMethod("Compare", c(e1 ="rnum", e2 = "rnum"),
          function(e1, e2) {
              d <- min(e1@d, e2@d)
              callGeneric(round(e1, d), round(e2, d))
          })




set.seed(867)

x1 <- rnum(10*runif(5), d=1L)
x2 <- rnum(10*runif(5), d=2L)

x1+1
x2*2
x1-x2

## Simple examples to illustrate callNextMethod with and without arguments
B0 <- setClass("B0", slots = c(s0 = "numeric"))

## and a function to illustrate callNextMethod

f <- function(x, text = "default") {
    str(x) # print a summary
    paste(text, ":", class(x))
}

setGeneric("f")
setMethod("f", "B0", function(x, text = "B0") {
    cat("B0 method called with s0 =", x@s0, "\n")
    callNextMethod()
})

b0 <- B0(s0 = 1)

## call f() with 2 arguments: callNextMethod passes both to the default method
f(b0, "first test")

## call f() with 1 argument:  the default "B0" is not passed by callNextMethod
f(b0)

## Now, a class that extends B0, with no methods for f()
B1 <- setClass("B1", slots = c(s1 = "character"), contains = "B0")
b1 <- B1(s0 = 2, s1 = "Testing B1")

## the two cases work as before, by inheriting the "B0" method

f(b1, b1@s1)

f(b1)

B2 <- setClass("B2", contains = "B1")

## And, a method for "B2" that calls with explicit arguments.
## Note that the method selection in callNextMethod
## uses the class of the *argument* to consistently select the "B0" method

setMethod("f", "B2", function(x, text = "B1 method") {
    y <- B1(s0 = -x@s0, s1 ="Modified x")
    callNextMethod(y, text)
})

b2 <- B2(s1 = "Testing B2", s0 = 10)

f(b2, b2@s1)

f(b2)


## Be careful:  the argument passed must be legal for the method selected
## Although the argument here is numeric, it's still the "B0" method that's called
setMethod("f", "B2", function(x, text = "B1 method") {
    callNextMethod(x@s0, text)
})

##  Now the call will cause an error:

tryCatch(f(b2), error = function(e) cat(e$message,"\n"))


\dontshow{
##$
removeClass("B2"); removeClass("B1"); removeClass("B0")

removeGeneric("f")

removeMethods(all=FALSE,"Arith"); removeMethods(all=FALSE,"Compare")
removeMethods(all=FALSE,"Math"); removeMethods(all=FALSE,"Math2")

## tests of multiple callNextMethod
setClass("m1", slots = c(count = "numeric"), contains = "matrix",
         prototype = prototype(count = 0))
mm1 <- new("m1", matrix(1:12, 3,4))
setMethod("[", "m1", function(x, i, j, ..., drop) callNextMethod())

setClass("m2", slots = c(sum = "numeric"), contains = "m1")

setMethod("Ops", c("m1", "m1"), function(e1, e2) {
    as(e1, "matrix") <- callNextMethod()
    e1@count <- max(e1@count, e2@count)+1
    e1})

mm2 <- new("m2", matrix(1:12, 3, 4), sum = sum(1:12))

stopifnot(identical(mm2[,2], 4:6))

setClass("m3", slots = c(rowtags = "character"),contains = "m2")

setMethod("[", signature(x="m3", i = "character", j = "missing",
                         drop = "missing"),
          function(x, i,j, ..., drop) {
              xx <- callNextMethod(x, match(i, x@rowtags),)
              x@.Data <- xx
              x@rowtags <- x@rowtags[match(i, x@rowtags)]
              x})

tm <- matrix(1:12, 4, 3)

mm3 <- new("m3", tm, rowtags = letters[1:4])

mmm <- mm3[c("b", "d")]

stopifnot(identical(mmm,
      new("m3", tm[c(2, 4),], rowtags = c("b", "d"))))

removeClass("m3")
removeClass("m2")
removeClass("m1")

removeMethods(all=FALSE,"[")
removeMethods(all=FALSE,"Ops")
}

}
\keyword{programming}
\keyword{classes}
\keyword{methods}