Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the function t return a t.test for objects with class set to "test"?

Tags:

r

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?

like image 377
M4RT1NK4 Avatar asked Mar 12 '16 20:03

M4RT1NK4


1 Answers

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.

like image 192
Stibu Avatar answered Oct 11 '22 19:10

Stibu