Reputation: 4145
why is predict
not a generic function? isGeneric('predict')
is FALSE
but isGeneric('summary')
and isGeneric('print')
is TRUE
. All of them have methods, which can be listed with methods('predict')
etc? So predict
is not a generic function as described here (also obvious from looking at class
) but still dispatches methods depending on the object passed to it (e.g. predict.lm
or predict.glm
). So there is a different way R dispatches methods? How can I test whether a function has methods so that all of the examples above are true? Yes, I can test the length of methods('predict')
but that produces a warning for functions without methods.
Upvotes: 4
Views: 1193
Reputation: 1629
My general understanding of S3 generics comes from the R Language manual where I'm lead to believe that a function func
cannot be a generic without calling UseMethod
in its body. So, without any fancy packages, you can use the following gist:
isFuncS3Generic <- function(func) {
funcBody <- body(func)
sum(grepl(pattern="UseMethod", x=funcBody)) != 0
}
edit: using your litmus test:
> isFuncS3Generic(print)
[1] TRUE
> isFuncS3Generic(predict)
[1] TRUE
> isFuncS3Generic(summary)
[1] TRUE
> isFuncS3Generic(glm)
[1] FALSE
@Hadley, I'm not really sure why this is a hard problem. Would you mind elaborating?
Upvotes: 2
Reputation: 94182
For starters, none of those functions are generic by your test:
> isGeneric('predict')
[1] FALSE
> isGeneric('summary')
[1] FALSE
> isGeneric('print')
[1] FALSE
Let's try again...
> isGeneric("summary")
[1] FALSE
> require(sp)
Loading required package: sp
> isGeneric("summary")
[1] TRUE
What's going on here? Well, isGeneric
only tests for S4 generic functions, and when I start R summary
is an S3 generic function. If a package wants to use S4 methods and classes and there already exists an S3 generic function then it can create an S4 generic.
So, initially summary
is:
> summary
function (object, ...)
UseMethod("summary")
<bytecode: 0x9e4fc08>
<environment: namespace:base>
which is an S3 generic. I get the sp
package...
> require(sp)
Loading required package: sp
> summary
standardGeneric for "summary" defined from package "base"
function (object, ...)
standardGeneric("summary")
<environment: 0x9f9d428>
Methods may be defined for arguments: object
Use showMethods("summary") for currently available ones.
and now summary
is an S4 standard generic.
S3 generic methods despatch (usually) by calling {generic}.{class}
, and this is what UseMethod("summary")
does in the S3 summary
generic function.
If you want to test if a function has methods for a particular class, then you probably have to test that it has an S4 method (using the functions for S4 method metadata) and an S3 method (by looking for a function called {generic}.{class}
, such as summary.glm
.
Great eh?
Upvotes: 15