| 15357 |
jmc |
1 |
\name{setMethod}
|
|
|
2 |
\alias{setMethod}
|
| 17454 |
jmc |
3 |
\alias{removeMethod}
|
| 15357 |
jmc |
4 |
\title{ Create and Save a Method }
|
|
|
5 |
\description{
|
|
|
6 |
Create and save a formal method for a given function and list of classes.
|
|
|
7 |
}
|
|
|
8 |
\usage{
|
| 26530 |
maechler |
9 |
setMethod(f, signature=character(), definition, where= topenv(parent.frame()),
|
|
|
10 |
valueClass = NULL, sealed = FALSE)
|
| 17454 |
jmc |
11 |
|
|
|
12 |
removeMethod(f, signature, where)
|
| 15357 |
jmc |
13 |
}
|
|
|
14 |
\arguments{
|
|
|
15 |
\item{f}{ The character-string name of the generic function. }
|
|
|
16 |
\item{signature}{ A match of formal argument names for \code{f} with
|
| 19029 |
hornik |
17 |
the character-string names of corresponding classes. This
|
|
|
18 |
argument can also just be the vector of class names, in which case
|
|
|
19 |
the first name corresponds to the first formal argument, the
|
|
|
20 |
next to the second formal argument, etc.}
|
| 15826 |
jmc |
21 |
\item{definition}{ A function definition, which will become the method
|
| 19029 |
hornik |
22 |
called when the arguments in a call to \code{f} match the
|
|
|
23 |
classes in \code{signature}, directly or through inheritance. }
|
| 26530 |
maechler |
24 |
\item{where}{the database in which to store the definition of the
|
|
|
25 |
method; % FIXME: by default, the ... environment.
|
| 17454 |
jmc |
26 |
|
| 19029 |
hornik |
27 |
For \code{removeMethod}, the default is the location of the (first)
|
|
|
28 |
instance of the method for this signature.}
|
| 15357 |
jmc |
29 |
\item{valueClass}{ If supplied, this argument asserts that the
|
| 19029 |
hornik |
30 |
method will return a value of this class. (At present this
|
|
|
31 |
argument is stored but not explicitly used.) }
|
| 23493 |
jmc |
32 |
\item{sealed}{ If \code{TRUE}, the method so defined cannot be
|
|
|
33 |
redefined by another call to \code{setMethod} (although it can
|
|
|
34 |
be removed and then re-assigned). Note that this argument is an
|
|
|
35 |
extension to the definition of \code{setMethod} in the reference.}
|
| 15357 |
jmc |
36 |
}
|
| 17454 |
jmc |
37 |
\value{
|
| 19029 |
hornik |
38 |
These functions exist for their side-effect, in setting or removing a
|
|
|
39 |
method in the object defining methods for the specified generic.
|
| 17454 |
jmc |
40 |
|
| 19029 |
hornik |
41 |
The value returned by \code{removeMethod} is \code{TRUE} if a method
|
|
|
42 |
was found to be removed.
|
| 17454 |
jmc |
43 |
}
|
| 15357 |
jmc |
44 |
\details{
|
|
|
45 |
R methods for a particular generic function are stored in an object
|
| 23678 |
jmc |
46 |
of class \code{\link{MethodsList}}. The effect of calling
|
| 15826 |
jmc |
47 |
\code{setMethod} is to store \code{definition} in a \code{MethodsList}
|
| 23678 |
jmc |
48 |
object on database \code{where}. If \code{f} doesn't
|
| 15357 |
jmc |
49 |
exist as a generic function, but there is an ordinary function of
|
|
|
50 |
the same name and the same formal arguments, a new generic function
|
|
|
51 |
is created, and the previous non-generic version of \code{f} becomes
|
| 23678 |
jmc |
52 |
the default method. This is equivalent to the programmer calling
|
|
|
53 |
\code{\link{setGeneric}} for the same function; it's better practice
|
|
|
54 |
to do the call explicitly, since it shows that you intend to turn
|
|
|
55 |
\code{f} into a generic function.
|
| 15357 |
jmc |
56 |
|
| 23678 |
jmc |
57 |
Methods are stored in a hierarchical structure: see
|
|
|
58 |
\link{Methods} for how the objects are used to select a method, and
|
|
|
59 |
\code{\link{MethodsList}} for functions that manipulate the objects.
|
|
|
60 |
|
|
|
61 |
The class
|
| 15357 |
jmc |
62 |
names in the signature can be any formal class, plus predefined basic
|
|
|
63 |
classes such as \code{"numeric"}, \code{"character"}, and
|
|
|
64 |
\code{"matrix"}. Two additional special class names can appear:
|
|
|
65 |
\code{"ANY"}, meaning that this argument can have any class at all;
|
|
|
66 |
and \code{"missing"}, meaning that this argument \emph{must not}
|
|
|
67 |
appear in the call in order to match this signature. Don't confuse
|
|
|
68 |
these two: if an argument isn't mentioned in a signature, it
|
|
|
69 |
corresponds implicitly to class \code{"ANY"}, not to
|
| 25118 |
hornik |
70 |
\code{"missing"}. See the example below. Old-style (\dQuote{S3})
|
|
|
71 |
classes can also be used, if you need compatibility with these, but
|
|
|
72 |
you should definitely declare these classes by calling
|
| 23678 |
jmc |
73 |
\code{\link{setOldClass}} if you want S3-style inheritance to work.
|
| 15357 |
jmc |
74 |
|
| 23678 |
jmc |
75 |
|
| 15357 |
jmc |
76 |
While \code{f} can correspond to methods defined on several packages
|
| 19087 |
jmc |
77 |
or environments, the underlying model is that these together make up
|
| 15357 |
jmc |
78 |
the definition for a single generic function. When R proceeds to
|
|
|
79 |
select and evaluate methods for \code{f}, the methods on the current
|
| 23678 |
jmc |
80 |
search list are merged to form a single methods list. When \code{f}
|
| 25118 |
hornik |
81 |
is called and a method is \dQuote{dispatched}, the evaluator matches the
|
| 23678 |
jmc |
82 |
classes of the actual arguments to the signatures of the available
|
|
|
83 |
methods. When a match is found, the body of the corresponding
|
|
|
84 |
method is evaluated (in R, the body is evaluated in the lexical
|
|
|
85 |
context of the method), but without rematching the arguments to
|
|
|
86 |
\code{f}.
|
|
|
87 |
|
|
|
88 |
It is possible, however, to have some differences between the
|
|
|
89 |
formal arguments to a method supplied to \code{setMethod} and those
|
|
|
90 |
of the generic. Roughly, if the generic has \dots as one of its
|
|
|
91 |
arguments, then the method may have extra formal arguments, which
|
|
|
92 |
will be matched from the arguments matching \dots in the call to
|
|
|
93 |
\code{f}. (What actually happens is that a local function is
|
|
|
94 |
created inside the method, with its formal arguments, and the method
|
|
|
95 |
is re-defined to call that local function.)
|
| 26530 |
maechler |
96 |
|
| 23678 |
jmc |
97 |
Method dispatch tries to match the class of the actual arguments in a
|
|
|
98 |
call to the available methods collected for \code{f}. Roughly, for
|
|
|
99 |
each formal argument in turn, we look for the best match (the exact
|
|
|
100 |
same class or the nearest element in the value of
|
|
|
101 |
\code{\link{extends}} for that class) for which there is any
|
|
|
102 |
possible method matching the remaining arguments. See
|
|
|
103 |
\link{Methods} for more details.
|
|
|
104 |
|
| 15357 |
jmc |
105 |
}
|
|
|
106 |
\references{
|
| 25118 |
hornik |
107 |
The R package \pkg{methods} implements, with a few exceptions, the
|
|
|
108 |
programming interface for classes and methods in the book
|
|
|
109 |
\emph{Programming with Data} (John M. Chambers, Springer, 1998), in
|
|
|
110 |
particular sections 1.6, 2.7, 2.8, and chapters 7 and 8.
|
| 15357 |
jmc |
111 |
|
| 25118 |
hornik |
112 |
While the programming interface for the \pkg{methods} package follows
|
|
|
113 |
the reference, the R software is an original implementation, so
|
|
|
114 |
details in the reference that reflect the S4 implementation may appear
|
| 21001 |
jmc |
115 |
differently in R. Also, there are extensions to the programming
|
|
|
116 |
interface developed more recently than the reference. For a
|
| 26530 |
maechler |
117 |
discussion of details and ongoing development, see the web page
|
| 21001 |
jmc |
118 |
\url{http://developer.r-project.org/methodsPackage.html} and the
|
|
|
119 |
pointers from that page.
|
| 15357 |
jmc |
120 |
}
|
|
|
121 |
\examples{
|
| 27464 |
ripley |
122 |
\dontshow{ require(stats)
|
| 15357 |
jmc |
123 |
setClass("track",
|
|
|
124 |
representation(x="numeric", y = "numeric"))
|
| 17454 |
jmc |
125 |
setClass("trackCurve", representation("track",
|
|
|
126 |
smooth = "numeric"))
|
| 21001 |
jmc |
127 |
setClass("trackMultiCurve", representation(x="numeric", y="matrix", smooth="matrix"),
|
|
|
128 |
prototype = list(x=numeric(), y=matrix(0,0,0), smooth=
|
|
|
129 |
matrix(0,0,0)))
|
| 15357 |
jmc |
130 |
}
|
| 17376 |
jmc |
131 |
|
| 15357 |
jmc |
132 |
## methods for plotting track objects (see the example for \link{setClass})
|
|
|
133 |
##
|
|
|
134 |
## First, with only one object as argument:
|
| 17376 |
jmc |
135 |
setMethod("plot", signature(x="track", y="missing"),
|
|
|
136 |
function(x, y, ...) plot(slot(x, "x"), slot(x, "y"), ...)
|
| 15357 |
jmc |
137 |
)
|
|
|
138 |
## Second, plot the data from the track on the y-axis against anything
|
|
|
139 |
## as the x data.
|
| 17376 |
jmc |
140 |
setMethod("plot", signature(y = "track"),
|
|
|
141 |
function(x, y, ...) plot(x, slot(y, "y"), ...)
|
| 15357 |
jmc |
142 |
)
|
|
|
143 |
## and similarly with the track on the x-axis (using the short form of
|
|
|
144 |
## specification for signatures)
|
| 17376 |
jmc |
145 |
setMethod("plot", "track",
|
|
|
146 |
function(x, y, ...) plot(slot(x, "y"), y, ...)
|
| 15357 |
jmc |
147 |
)
|
| 17239 |
jmc |
148 |
t1 <- new("track", x=1:20, y=(1:20)^2)
|
| 15357 |
jmc |
149 |
tc1 <- new("trackCurve", t1)
|
| 16707 |
jmc |
150 |
slot(tc1, "smooth") <- smooth.spline(slot(tc1, "x"), slot(tc1, "y"))$y #$
|
| 17376 |
jmc |
151 |
plot(t1)
|
|
|
152 |
plot(qnorm(ppoints(20)), t1)
|
| 18151 |
jmc |
153 |
## An example of inherited methods, and of conforming method arguments
|
|
|
154 |
## (note the dotCurve argument in the method, which will be pulled out
|
|
|
155 |
## of ... in the generic.
|
| 17376 |
jmc |
156 |
setMethod("plot", c("trackCurve", "missing"),
|
| 18151 |
jmc |
157 |
function(x, y, dotCurve = FALSE, ...) {
|
| 17376 |
jmc |
158 |
plot(as(x, "track"))
|
| 15357 |
jmc |
159 |
if(length(slot(x, "smooth") > 0))
|
| 18151 |
jmc |
160 |
lines(slot(x, "x"), slot(x, "smooth"),
|
|
|
161 |
lty = if(dotCurve) 2 else 1)
|
| 15357 |
jmc |
162 |
}
|
|
|
163 |
)
|
|
|
164 |
## the plot of tc1 alone has an added curve; other uses of tc1
|
|
|
165 |
## are treated as if it were a "track" object.
|
| 18151 |
jmc |
166 |
plot(tc1, dotCurve = TRUE)
|
| 17376 |
jmc |
167 |
plot(qnorm(ppoints(20)), tc1)
|
| 16576 |
jmc |
168 |
|
|
|
169 |
## defining methods for a special function.
|
| 16707 |
jmc |
170 |
## Although "[" and "length" are not ordinary functions
|
|
|
171 |
## methods can be defined for them.
|
| 16576 |
jmc |
172 |
setMethod("[", "track",
|
|
|
173 |
function(x, i, j, ..., drop) {
|
|
|
174 |
x@x <- x@x[i]; x@y <- x@y[i]
|
|
|
175 |
x
|
|
|
176 |
})
|
| 17376 |
jmc |
177 |
plot(t1[1:15])
|
| 16576 |
jmc |
178 |
|
| 16707 |
jmc |
179 |
setMethod("length", "track", function(x)length(x@y))
|
|
|
180 |
length(t1)
|
|
|
181 |
|
| 17761 |
jmc |
182 |
## methods can be defined for missing arguments as well
|
|
|
183 |
setGeneric("summary") ## make the function into a generic
|
|
|
184 |
|
|
|
185 |
## A method for summary()
|
|
|
186 |
## The method definition can include the arguments, but
|
|
|
187 |
## if they're omitted, class "missing" is assumed.
|
|
|
188 |
|
|
|
189 |
setMethod("summary", "missing", function() "<No Object>")
|
|
|
190 |
|
| 26000 |
ripley |
191 |
\dontshow{
|
| 17761 |
jmc |
192 |
|
|
|
193 |
stopifnot(identical(summary(), "<No Object>"))
|
|
|
194 |
|
| 16707 |
jmc |
195 |
## for the primitives
|
|
|
196 |
## inherited methods
|
|
|
197 |
|
|
|
198 |
length(tc1)
|
|
|
199 |
tc1[-1]
|
|
|
200 |
|
| 16576 |
jmc |
201 |
## make sure old-style methods still work.
|
|
|
202 |
t11 <- t1[1:15]
|
|
|
203 |
identical(t1@y[1:15], t11@y)
|
|
|
204 |
|
|
|
205 |
## S3 methods, with nextMethod
|
|
|
206 |
form <- y ~ x
|
|
|
207 |
form[1]
|
| 16866 |
jmc |
208 |
|
|
|
209 |
## S3 arithmetic methods
|
|
|
210 |
ISOdate(1990, 12, 1)- ISOdate(1980, 12, 1)
|
|
|
211 |
|
| 19473 |
jmc |
212 |
## group methods
|
| 16866 |
jmc |
213 |
|
| 19473 |
jmc |
214 |
setMethod("Arith", c("track", "numeric"), function(e1, e2){e1@y <-
|
|
|
215 |
callGeneric(e1@y , e2); e1})
|
| 16866 |
jmc |
216 |
|
| 19473 |
jmc |
217 |
|
| 16866 |
jmc |
218 |
t1 - 100.
|
|
|
219 |
|
| 19473 |
jmc |
220 |
t1/2
|
|
|
221 |
|
|
|
222 |
|
| 16866 |
jmc |
223 |
## check it hasn't screwed up S3 methods
|
|
|
224 |
ISOdate(1990, 12, 1)- ISOdate(1980, 12, 1)
|
|
|
225 |
|
| 21865 |
jmc |
226 |
## test the .Generic mechanism
|
|
|
227 |
|
|
|
228 |
setMethod("Compare", signature("track", "track"),
|
|
|
229 |
function(e1,e2) {
|
|
|
230 |
switch(.Generic,
|
|
|
231 |
"==" = e1@y == e2@y,
|
|
|
232 |
NA)
|
|
|
233 |
})
|
|
|
234 |
|
|
|
235 |
#stopifnot(all(t1==t1))
|
|
|
236 |
#stopifnot(identical(t1<t1, NA))
|
|
|
237 |
|
|
|
238 |
|
| 21001 |
jmc |
239 |
## A test of nested calls to "[" with matrix-style arguments
|
|
|
240 |
## applied to data.frames (S3 methods)
|
|
|
241 |
|
|
|
242 |
setMethod("[", c("trackMultiCurve", "numeric", "numeric"), function(x, i, j, ..., drop) {
|
|
|
243 |
### FIXME: a better version has only 1st arg in signature
|
|
|
244 |
### and uses callNextMethod, when this works with primitives.
|
|
|
245 |
x@y <- x@y[i, j, drop=FALSE]
|
|
|
246 |
x@x <- x@x[i]
|
|
|
247 |
x
|
|
|
248 |
})
|
|
|
249 |
|
|
|
250 |
|
|
|
251 |
"testFunc" <-
|
|
|
252 |
function(cur) {
|
|
|
253 |
sorted <- cur[order(cur[,1]),]
|
|
|
254 |
sorted[ !is.na(sorted[,1]), ]
|
|
|
255 |
}
|
|
|
256 |
|
|
|
257 |
Nrow <- 1000 # at one time, values this large triggered a bug in gc/protect
|
|
|
258 |
## the loop here was a trigger for the bug
|
|
|
259 |
Niter <- 10
|
|
|
260 |
for(i in 1:Niter) {
|
|
|
261 |
yy <- matrix(rnorm(10*Nrow), 10, Nrow)
|
|
|
262 |
tDF <- as.data.frame(yy)
|
|
|
263 |
testFunc(tDF)
|
|
|
264 |
}
|
|
|
265 |
|
|
|
266 |
|
|
|
267 |
tMC <- new("trackMultiCurve", x=seq(length=Nrow), y = yy)
|
|
|
268 |
## not enough functions have methods for this class to use testFunc
|
|
|
269 |
|
|
|
270 |
stopifnot(identical(tMC[1:10, 1:10]@y, yy[1:10, 1:10]))
|
|
|
271 |
|
|
|
272 |
|
| 17454 |
jmc |
273 |
## verify we can remove methods and generic
|
|
|
274 |
|
| 17761 |
jmc |
275 |
removeMethods("-")
|
| 23305 |
ripley |
276 |
removeMethod("length", "track")
|
| 21865 |
jmc |
277 |
removeMethods("Arith")
|
|
|
278 |
removeMethods("Compare")
|
| 17454 |
jmc |
279 |
|
| 17761 |
jmc |
280 |
## repeat the test one more time on the primitives
|
|
|
281 |
|
|
|
282 |
length(ISOdate(1990, 12, 1)- ISOdate(1980, 12, 1))
|
|
|
283 |
|
| 21875 |
jmc |
284 |
## methods for %*%, which isn't done by the same C code as other ops
|
|
|
285 |
|
|
|
286 |
setClass("foo", representation(m="matrix"))
|
|
|
287 |
m1 <- matrix(1:12,3,4)
|
|
|
288 |
f1 = new("foo", m=m1)
|
|
|
289 |
f2 = new("foo", m=t(m1))
|
|
|
290 |
|
|
|
291 |
setMethod("\%*\%", c("foo", "foo"),
|
|
|
292 |
function(x,y)callGeneric(x@m, y@m))
|
|
|
293 |
|
|
|
294 |
stopifnot(identical(f1\%*\%f2, m1\%*\% t(m1)))
|
|
|
295 |
|
|
|
296 |
removeMethods("\%*\%")
|
|
|
297 |
|
| 17761 |
jmc |
298 |
removeMethods("plot")
|
|
|
299 |
|
|
|
300 |
stopifnot(existsFunction("plot", FALSE) && !isGeneric("plot", 1))
|
|
|
301 |
|
| 17454 |
jmc |
302 |
## methods for plotData
|
|
|
303 |
plotData <- function(x, y, ...) plot(x, y, ...)
|
|
|
304 |
|
|
|
305 |
setGeneric("plotData")
|
|
|
306 |
|
|
|
307 |
setMethod("plotData", signature(x="track", y="missing"),
|
|
|
308 |
function(x, y, ...) plot(slot(x, "x"), slot(x, "y"), ...)
|
|
|
309 |
)
|
|
|
310 |
## and now remove the whole generic
|
| 17761 |
jmc |
311 |
removeGeneric("plotData")
|
|
|
312 |
|
| 17454 |
jmc |
313 |
stopifnot(!exists("plotData", 1))
|
|
|
314 |
|
| 18413 |
jmc |
315 |
## Tests of method inheritance & multiple dispatch
|
|
|
316 |
setClass("A0", representation(a0 = "numeric"))
|
| 18380 |
jmc |
317 |
|
| 18413 |
jmc |
318 |
setClass("A1", representation("A0", a1 = "character"))
|
|
|
319 |
|
|
|
320 |
setClass("B0" ,representation(b0 = "numeric"))
|
|
|
321 |
|
|
|
322 |
setClass("B1", "B0")
|
|
|
323 |
|
|
|
324 |
setClass("B2", representation("B1", b2 = "logical"))
|
|
|
325 |
|
|
|
326 |
setClass("AB0", representation("A1", "B2", ab0 = "matrix"))
|
|
|
327 |
|
|
|
328 |
f1 <- function(x, y)"ANY"
|
|
|
329 |
|
|
|
330 |
setGeneric("f1")
|
|
|
331 |
|
|
|
332 |
setMethod("f1", c("A0", "B1"), function(x, y)"A0 B1")
|
|
|
333 |
setMethod("f1", c("B1", "A0"), function(x, y)"B1 A0")
|
|
|
334 |
|
|
|
335 |
a0 <- new("A0")
|
|
|
336 |
a1 <- new("A1")
|
|
|
337 |
b0 <- new("B0")
|
|
|
338 |
b1 <- new("B1")
|
|
|
339 |
b2 <- new("B2")
|
|
|
340 |
|
|
|
341 |
deparseText <- function(expr)
|
|
|
342 |
paste(deparse(expr), collapse = "\\ ")
|
|
|
343 |
|
|
|
344 |
mustEqual <- function(e1, e2){
|
|
|
345 |
if(!identical(e1, e2))
|
|
|
346 |
stop(paste("!identical(", deparseText(substitute(e1)),
|
|
|
347 |
", ", deparseText(substitute(e2)), ")", sep=""))
|
| 15357 |
jmc |
348 |
}
|
| 18413 |
jmc |
349 |
|
|
|
350 |
mustEqual(f1(a0, b0), "ANY")
|
|
|
351 |
mustEqual(f1(a1,b0), "ANY")
|
|
|
352 |
mustEqual(f1(a1,b1), "A0 B1")
|
|
|
353 |
mustEqual(f1(b1,a1), "B1 A0")
|
|
|
354 |
mustEqual(f1(b1,b1), "ANY")
|
|
|
355 |
|
| 20330 |
jmc |
356 |
## remove classes: order matters so as not to undefine earlier classes
|
|
|
357 |
for(.cl in c("AB0", "A1", "A0", "B2", "B1", "B0"))
|
| 18413 |
jmc |
358 |
removeClass(.cl)
|
|
|
359 |
|
|
|
360 |
removeGeneric("f1")
|
|
|
361 |
|
| 19670 |
jmc |
362 |
## test of nonstandard generic definition
|
| 18413 |
jmc |
363 |
|
| 19670 |
jmc |
364 |
setGeneric("doubleAnything", function(x) {
|
|
|
365 |
methodValue <- standardGeneric("doubleAnything")
|
|
|
366 |
c(methodValue, methodValue)
|
|
|
367 |
})
|
| 18413 |
jmc |
368 |
|
| 19670 |
jmc |
369 |
setMethod("doubleAnything", "ANY", function(x)x)
|
|
|
370 |
|
|
|
371 |
setMethod("doubleAnything", "character",
|
|
|
372 |
function(x)paste("<",x,">",sep=""))
|
|
|
373 |
|
|
|
374 |
mustEqual(doubleAnything(1:10), c(1:10, 1:10))
|
|
|
375 |
mustEqual(doubleAnything("junk"), rep("<junk>",2))
|
|
|
376 |
|
|
|
377 |
removeGeneric("doubleAnything")
|
|
|
378 |
|
|
|
379 |
|
| 16576 |
jmc |
380 |
}
|
| 18413 |
jmc |
381 |
}
|
| 15357 |
jmc |
382 |
|
| 17454 |
jmc |
383 |
\seealso{ \link{Methods}, \code{\link{MethodsList}} for details of the
|
|
|
384 |
implementation}
|
| 15357 |
jmc |
385 |
|
|
|
386 |
\keyword{programming}
|
|
|
387 |
\keyword{classes}
|
| 17454 |
jmc |
388 |
\keyword{classes}
|
| 15357 |
jmc |
389 |
\keyword{methods}
|