[Rd] Questions about S4 style methods and generics
Saikat DebRoy
saikat@stat.wisc.edu
09 May 2002 12:10:39 -0500
>>>>> "John" == John Chambers <jmc@research.bell-labs.com> writes:
John> Saikat DebRoy wrote:
>>
>> I have some questions about S4 style methods and generics.
>>
>> First of all, is there any way of using default values for arguments
>> in the generics/methods? My own experiments show that such arguments
>> are always ignored.
John> Yes there is and no they are not.
John> But there are a couple of points to keep in mind.
John> The definition of method dispatch is that the _body_ of the selected
John> method is evaluated, without rematching arguments. That means that it's
John> the default values in the (generic) function definition that will be
John> found in the context of the call.
I was in a situation where there is no default method.
> setGeneric("foo", function(x, y=0) standardGeneric("foo"))
[1] "foo"
> setMethod("foo", signature(x="numeric", y="numeric"), function(x, y) x+y)
[1] "foo"
> foo(1, 2)
[1] 3
> foo(1)
Error in foo(1) : No direct or inherited method for function "foo" for this call
So are the default values are substituted in the function call after the
method signature is matched? I tried a few other variations. In all
cases it ended up calling the default method if any or gave the same
error if there was no default method. I then moved to three arguments
and got some surprising (to me) results.
R> setGeneric("foo", function(x=1, y=2,z=3) standardGeneric("foo"))
[1] "foo"
R> setMethod("foo", signature(x="ANY", y="ANY",z="ANY"), function(x, y,z) cat("in default method\n"))
[1] "foo"
R> setMethod("foo", signature(x="numeric", y="numeric",z="numeric"), function(x, y,z) cat("in other method\n"))
[1] "foo"
R> foo(5,6,7)
in other method
R> foo(5,6)
Error in foo(1, 2) : No matching method for function "NA" (argument "z", with class missing)
R> foo(5)
in default method
R> getMethods("foo")
x = "ANY", y = "ANY", z = "ANY":
function (x, y, z)
cat("in default method\n")
x = "numeric", y = "numeric", z = "numeric":
function (x, y, z)
cat("in other method\n")
x = "numeric", y = "numeric", z = "ANY":
function (x, y, z)
cat("in default method\n")
##: (inherited from x = "ANY", y = "ANY", z = "ANY")
x = "numeric", y = "missing":
function (x, y, z)
cat("in default method\n")
##: (inherited from x = "ANY", y = "ANY", z = "ANY")
John> An example:
John> R> bar <- function(x, y = 0)x+y
John> R> setGeneric("bar")
John> R> bar
John> function (x, y = 0)
John> standardGeneric("bar")
John> <environment: 0x8622a18>
John> R> setMethod("bar", "character", function(x, y) paste(x,y))
John> [1] "bar"
John> R> bar(1,2)
John> [1] 3
John> R> bar(99)
John> [1] 99
John> R> bar("test")
John> [1] "test 0"
John> OTOH, the default expressions for the arguments in the method are
John> available in the method object. You can extract them by getting the
John> method and retrieving, for example, def$y. It seems a sufficiently
John> asked-for item that we'll provide a tool for it.
John> Maybe
John> evaluateMethodDefault("y")
John> ?? The point is to allow access but not burden the standard method
John> dispatch with re-matching arguments.
>> The green book seems to be silent on this
>> matter.
>>
>> The second question is about using a non-trivial function body for
>> generics. Page 351 of the green book gives an example of this and the
>> documentation for setGeneric seems to suggest I should be able to do
>> this at least by using myDispatch=TRUE. However, the current
>> implementation seems to set the body of the generic definition to a
>> call to standardGeneric all the time. Is this a bug or a modification
>> of the green book description?
John> It's a bug. Having said that, though, nonstandard generic functions are
John> slightly deprecated. There are some potential efficiency enhancements
John> for dispatch that might be introduced but that would likely depend on
John> the function being a standard generic.
John> Also, experience is that people get a little confused and sometimes
John> provide a definition of the generic that doesn't call
John> standardGeneric("foo") and so does not give them the method dispatch
John> they expected.
John> But it's a bug & will be fixed. Meanwhile, there is a workaround, if
John> you're willing to be a bit klunky. You define the generic and then
John> replace the body, being careful to preserve the function's environment.
John> Another example:
John> R> foo <- function(x) x
John> R> setGeneric("foo")
John> [1] "foo"
John> R> body(foo, envir = environment(foo)) <-
John> + quote({cat("Here we go!\n"); standardGeneric("foo")})
John> R> setMethod("foo", "numeric", function(x)sum(x))
John> [1] "foo"
John> R> foo(1:10)
John> Here we go!
John> [1] 55
John> R> foo("test")
John> Here we go!
John> [1] "test"
>>
>> Thanks,
>>
>> Saikat
>> --
>> Department of Statistics Email: saikat@stat.wisc.edu
>> University of Wisconsin - Madison Phone: (608) 263 5948
>> 1210 West Dayton Street Fax: (608) 262 0032
>> Madison, WI 53706-1685
>> -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
>> r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
>> Send "info", "help", or "[un]subscribe"
>> (in the "body", not the subject !) To: r-devel-request@stat.math.ethz.ch
>> _._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !) To: r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._