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 methoddefinition. It then results in a call to the first inherited methodafter the current method, with the arguments to the current methodpassed down to the next method. The value of that method call is thevalue 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}, theeffect 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 definedto be that method which \emph{would} have been called if the currentmethod did not exist. This is more-or-less literally what happens: Thecurrent method (to be precise, the method with signature given by the\code{defined} slot of the method from which \code{callNextMethod} iscalled) is deleted from a copy of the methods for the current generic,and \code{\link{selectMethod}} is called to find the next method (theresult is cached in the method object where the call occurred, so the search typicallyhappens only once per session per combination of argument classes).The next method is defined from the \emph{signature} of the currentmethod, not from the actual classes of the arguments.In particular, modifying any of the arguments has no effect on theselection.As a result, the selected next method can be called with invalidarguments if the calling function assigns objects of a differentclass 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 ismore precisely as follows. Arguments that were missing in the currentcall are still missing (remember that \code{"missing"} is a validclass in a method signature). For a formal argument, say \code{x}, thatappears in the original call, there is a corresponding argument in thenext method call equivalent to \code{x = x}. In effect, thismeans that the next method sees the same actual arguments, butarguments are evaluated only once.}\section{Ambiguous Selection}{There are two fairly common situations in which the choice of a nextmethod is ambiguous, even when the original set of methods uniquelydefines all method selection unambiguously.In these situations, \code{callNextMethod()} should be replaced,either by a call to a specific function or by recalling the genericwith 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 casethat the first or the second argument comes from the class, and athird for the case that both arguments come from the class.If that last method uses \code{callNextMethod}, the other two methodsare equally valid. The ambiguity is exactly the same that requireddefining the two-argument method in the first place.In fact, the two possibilities are equally valid conceptually as wellas formally.As in the example below, the logic of the application usually requiresselecting a computation explicitly or else calling the genericfunction with modified arguments to select an appropriate method.The other likely source of ambiguity arises from a class that inheritsdirectly from more than one other class (a \dQuote{mixin} in standardterminology).If the generic has methods corresponding to both superclasses, amethod 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 methodinstead.These ambiguities are not the result of bad design, but they dorequire workarounds.Other ambiguities usually reflect inconsistencies in the tree ofinheritances, such as a class appearing in more than one place amongthe superclasses.Such cases should be rare, but with the independent definition ofclasses 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 thecurrent 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" digitsrnum <- 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 vectorsetMethod("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))elsecallGeneric(as.numeric(e1), e2)})## For comparisons, callNextMethod with the rounded argumentssetMethod("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+1x2*2x1-x2## Simple examples to illustrate callNextMethod with and without argumentsB0 <- setClass("B0", slots = c(s0 = "numeric"))## and a function to illustrate callNextMethodf <- function(x, text = "default") {str(x) # print a summarypaste(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 methodf(b0, "first test")## call f() with 1 argument: the default "B0" is not passed by callNextMethodf(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" methodf(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" methodsetMethod("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 calledsetMethod("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 callNextMethodsetClass("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)+1e1})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 <- xxx@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}