I'm reading Hadley Wickham's book Advanced R, specifically the OO fied guide (http://adv-r.had.co.nz/OO-essentials.html). The first exercise in that chapter is as follows:
Read the source code for t() and t.test() and confirm that t.test() is an S3 generic and not an S3 method. What happens if you create an object with class test and call t() with it?
If I understood the chapter correctly, we can confirm that t() and t.test() are generic, because they use the UseMethod() function in the source code. methods(t) returns t.data.frame, t.default and t.ts* as the methods of function t(). Why then, if both are S3 generics and t does not have a t.test method, does the following code return the t test?
a <- structure(1:4, class = "test")
t(a)
My prediction would be that t would use the default method for class "test" and t.default(a) does the transpose as logically I suppose it should. Where then does the t.test come from?
If you run t(a)
, where a
is your object of class test
, then UseMethod("t")
is called. This will check what the class of the first argument that you provided to t()
is. The class is test
and R will now
look for a function t.test()
. Since t.test()
exists, t.test(a)
is run. This is called "method dispatch".
Only if t.test()
did not exist, R would resort to calling t.default()
. You can actually even see this happen, by detaching the stats
package before running t(a)
:
a <- structure(1:4, class = "test")
detach("package:stats")
t(a)
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## attr(,"class")
## [1] "test"
The question is now, why t.test
is not contained in the list, when you run methods("t")
. When you look at the source code of methods()
, you will notice that it calls .S3methods()
. This function compiles the names of all the methods of t
. However, at some point, it removes the function names that are contained in S3MethodsStopList
:
info <- info[grep(name, row.names(info)), ]
info <- info[!row.names(info) %in% S3MethodsStopList,
]
(If I run edit(.S3methods) in RStudio, these are lines 47 and 48).
S3MethodsStopList
is defined earlier (on line 15):
S3MethodsStopList <- tools:::.make_S3_methods_stop_list(NULL)
The function tools:::.make_S3_methods_stop_list()
seems not to be documented, but it just seems to return a hardcoded list of function names that contain a dot, but are actually not methods. t.test()
is one of them:
grep("^t\\.", tools:::.make_S3_methods_stop_list(NULL), value = TRUE)
## Hmisc6 calibrator mosaic mratios1
## "t.test.cluster" "t.fun" "t.test" "t.test.ration"
## mratios2 mratios3 stats6
## "t.test.ratio.default" "t.test.ratio.formula"
In short, methods()
does explicitly filter out functions that are known not to be methods. Method dispatching, on the other hand, simply looks for a function with an appropriate name.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With