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. 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?
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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
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.
Yes there is and no they are not.
But there are a couple of points to keep in mind.
The definition of method dispatch is that the _body_ of the selected
method is evaluated, without rematching arguments. That means that it's
the default values in the (generic) function definition that will be
found in the context of the call.
An example:
R> bar <- function(x, y = 0)x+y
R> setGeneric("bar")
R> bar
function (x, y = 0)
standardGeneric("bar")
<environment: 0x8622a18>
R> setMethod("bar", "character", function(x, y) paste(x,y))
[1] "bar"
R> bar(1,2)
[1] 3
R> bar(99)
[1] 99
R> bar("test")
[1] "test 0"
OTOH, the default expressions for the arguments in the method are
available in the method object. You can extract them by getting the
method and retrieving, for example, def$y. It seems a sufficiently
asked-for item that we'll provide a tool for it.
Maybe
evaluateMethodDefault("y")
?? The point is to allow access but not burden the standard method
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?
It's a bug. Having said that, though, nonstandard generic functions are
slightly deprecated. There are some potential efficiency enhancements
for dispatch that might be introduced but that would likely depend on
the function being a standard generic.
Also, experience is that people get a little confused and sometimes
provide a definition of the generic that doesn't call
standardGeneric("foo") and so does not give them the method dispatch
they expected.
But it's a bug & will be fixed. Meanwhile, there is a workaround, if
you're willing to be a bit klunky. You define the generic and then
replace the body, being careful to preserve the function's environment.
Another example:
R> foo <- function(x) x
R> setGeneric("foo")
[1] "foo"
R> body(foo, envir = environment(foo)) <-
+ quote({cat("Here we go!\n"); standardGeneric("foo")})
R> setMethod("foo", "numeric", function(x)sum(x))
[1] "foo"
R> foo(1:10)
Here we go!
[1] 55
R> foo("test")
Here we go!
[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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
John M. Chambers jmc@bell-labs.com
Bell Labs, Lucent Technologies office: (908)582-2681
700 Mountain Avenue, Room 2C-282 fax: (908)582-3340
Murray Hill, NJ 07974 web: http://www.cs.bell-labs.com/~jmc
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
"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.
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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
"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.
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?
Hmmm, well "substituted" may not be the best term to use.
What happens here is pretty much determined by the API, not R-specific.
Your question about defaults has come up before; should be in a
to-be-written FAQ.
Basically everything is standard S (R or S-Plus) up to the point that
standardGeneric is called. With an ordinary generic function, arguments
are matched but not evaluated, because of lazy evaluation.
Now the dispatch code examines as many arguments as are involved in
existing signatures (2 in your example). The class for each argument
inserted into the current signature for dispatch is:
- "missing" if the corresponding argument is missing from the call;
- the class of the evaluated actual argument otherwise.
Because of the first step, default expressions are not evaluated during
method selection; they obey the standard S rules of lazy evaluation, as
do arguments not needed for the signature.
(Not relevant to the question, but the dispatch is done first in C; if
there is no method matching the signature exactly, then S language code
is used to select a method by inheritance, and the selected method is
cached under the current signature.)
Your later example seems to be a bug of some sort, but I'll examine it
more closely. Thanks. (Dispatch on 3+ arguments probably hasn't had
much exercise!)
John
John M. Chambers jmc@bell-labs.com
Bell Labs, Lucent Technologies office: (908)582-2681
700 Mountain Avenue, Room 2C-282 fax: (908)582-3340
Murray Hill, NJ 07974 web: http://www.cs.bell-labs.com/~jmc
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
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
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._