Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

type/origin of R's 'as' function

R's S3 OO system is centered around generic functions that call methods depending on the class of the object the generic function is being called on. The crux is that the generic function calls the appropriate method, as opposed to other OO programming languages in which the method is defined within the class.

For example, the mean function is a generic function.

isGeneric("mean")
methods(mean)

This will print

TRUE
[1] mean,ANY-method          mean.Date                mean.default             mean.difftime           
[5] mean.IDate*              mean,Matrix-method       mean.POSIXct             mean.POSIXlt            
[9] mean,sparseMatrix-method mean,sparseVector-method
see '?methods' for accessing help and source code

I was exploring R a bit and found the as function. I am confused by the fact that R says the function is not generic, but it still has methods.

isGeneric("as")
methods(as)

TRUE
  [1] as.AAbin                                  as.AAbin.character                       
  [3] as.alignment                              as.allPerms                              
  [5] as.array                                  as.array.default                         
  [7] as.binary                                 as.bitsplits                             
  [9] as.bitsplits.prop.part                    as.call
  ...                                  

At the end there is a warning that says that as is not a generic.

 Warning message:
 In .S3methods(generic.function, class, parent.frame()) :
 function 'as' appears not to be S3 generic; found functions that look like S3 methods

Could someone explain me what the as function is and how is connected to as.list, as.data.frame etc? R says that as.list is a generic (where I am tempted to get a bit mad at the inconsistencies within R, because I would expect as.list to be a method for a list object from the as generic function). Please help.

like image 594
PejoPhylo Avatar asked Jan 14 '18 17:01

PejoPhylo


1 Answers

as is not an S3 generic, but notice that you got a TRUE. (I got a FALSE.) That means you have loaded a package that definesas as an S4-generic. S3-generics work via class dispatch that employs a *.default function and the UseMethod-function. The FALSE I get means there is no method defined for a generic as that would get looked up. One arguable reason for the lack of a generic as is that calling such a function with only one data object would not specify a "coercion destination". That means the destination needs to be built into the function name.

After declaring as to be Generic (note the capitalization which is a hint that this applies to S4 features:

setGeneric("as")  # note that I didn't really even need to define any methods

get('as')
#--- output----
standardGeneric for "as" defined from package "methods"

function (object, Class, strict = TRUE, ext = possibleExtends(thisClass, 
    Class)) 
standardGeneric("as")
<environment: 0x7fb1ba501740>
Methods may be defined for arguments: object, Class, strict, ext
Use  showMethods("as")  for currently available ones.

If I reboot R (and don't load any libraries that call setGeneric for 'as') I get:

get('as')
#--- output ---
function (object, Class, strict = TRUE, ext = possibleExtends(thisClass, 
    Class)) 
{
    if (.identC(Class, "double")) 
        Class <- "numeric"
    thisClass <- .class1(object)
    if (.identC(thisClass, Class) || .identC(Class, "ANY")) 
        return(object)
    where <- .classEnv(thisClass, mustFind = FALSE)
    coerceFun <- getGeneric("coerce", where = where)
    coerceMethods <- .getMethodsTable(coerceFun, environment(coerceFun), 
        inherited = TRUE)
    asMethod <- .quickCoerceSelect(thisClass, Class, coerceFun, 
        coerceMethods, where)
    .... trimmed the rest of the code

But you ask "why", always a dangerous question when discussing language design, of course. I've flipped through the last chapter of Statistical Models in S which is the cited reference for most of the help pages that apply to S3 dispatch and find no discussion of either coercion or the as function. There is an implicit definition of "S3 generic" requiring the use of UseMethod but no mention of why as was left out of that strategy. I think of two possibilities: it is to prevent any sort of inheritance ambiguity in the application of the coercion, or it is an efficiency decision.

I should probably add that there is an S4 setAs-function and that you can find all the S4-coercion functions with showMethods("coerce").

like image 101
IRTFM Avatar answered Sep 25 '22 13:09

IRTFM