Читать книгу The Big R-Book - Philippe J. S. De Brouwer - Страница 188

6.2. S3 Objects

Оглавление

S3 is probably the most simple implementation of an OO system that is still useful. In its simplicity, it is extremely versatile and user friendly (once you get your old C and C++ reflexes under control).

The function is.object() returns true both for S3 and S4 objects. There is no base function that allows directly to test if an object is S3, but there is a to test to check if an object is S4. So we can test if something is S3 as follows.

# is.S3 # Determines if an object is S3 # Arguments: # x -- an object # Returns: # boolean -- TRUE if x is S3, FALSE otherwise is.S3 <- function(x){is.object(x) & !isS4(x)} # Create two test objects: M <- matrix(1:16, nrow=4) df <- data.frame(M) # Test our new function: is.S3(M) ## [1] FALSE is.S3(df) ## [1] TRUE

However, it is not really necessary to create such function by ourselves. We can leverage the library pryr, which provides a function otype() that returns the type of object.

pryr

otype()

library(pryr) otype(M) ## [1] “base” otype(df) ## [1] “S3” otype(df$X1) # a vector is not S3 ## [1] “base” df$fac <-factor(df$X4) otype(df$fac) # a factor is S3 ## [1] “S3”

The methods are provided by the generic function.4 Those functions will do different things for different S3 objects.

If you would like to determine if a function is S3 generic, then you can check the source code for the use of the function useMethod(). This function will take care of the dispatching and hence decide which method to call for the given object.

useMethod()

However, this method is not foolproof because some primitive functions have this switch statement embedded in their C-code. For example, [, sum(), rbind(), and cbind() are generic functions, but this is not visible in their code in R.

Alternatively, it is possible to use the function ftype from the package pryr:

mean ## function (x, …) ## UseMethod(“mean”) ## <bytecode: 0x563423e48908> ## <environment: namespace:base> ftype(mean) ## [1] “s3” “generic” sum ## function (…, na.rm = FALSE) .Primitive(“sum”) ftype(sum) ## [1] “primitive” “generic”

R calls the functions that have this switch in their C-code “internal” “generic”.

The S3 generic function basically decides to what other function to dispatch its task. For example, the function print can be called with any base or S3 object and print will decide what to do based on its class. Try the function apropos() to find out what different methods exist (or type print. in RStudio.

apropos(“print.”) ## [1] “print.AsIs” ## [2] “print.by” ## [3] “print.condition” ## [4] “print.connection” ## [5] “print.data.frame” ## [6] “print.Date” ## [7] “print.default” ## [8] “print.difftime” ## [9] “print.Dlist” ## [10] “print.DLLInfo” ## [11] “print.DLLInfoList” ## [12] “print.DLLRegisteredRoutines” ## [13] “print.eigen” ## [14] “print.factor” ## [15] “print.function” ## [16] “print.hexmode” ## [17] “print.libraryIQR” ## [18] “print.listof” ## [19] “print.NativeRoutineList” ## [20] “print.noquote” ## [21] “print.numeric_version” ## [22] “print.octmode” ## [23] “print.packageInfo” ## [24] “print.POSIXct” ## [25] “print.POSIXlt” ## [26] “print.proc_time” ## [27] “print.restart” ## [28] “print.rle” ## [29] “print.simple.list” ## [30] “print.srcfile” ## [31] “print.srcref” ## [32] “print.summary.table” ## [33] “print.summaryDefault” ## [34] “print.table” ## [35] “print.warnings” ## [36] “printCoefmat” ## [37] “sprintf” apropos(“mean.”) ## [1] “.colMeans” “.rowMeans” “colMeans” ## [4] “kmeans” “mean.Date” “mean.default” ## [7] “mean.difftime” “mean.POSIXct” “mean.POSIXlt” ## [10] “rowMeans”

This approach shows all functions that include “print.” in their name and are not necessarily the methods of the function print. Hence, amore elegant ways is to use the purpose build function methods().

methods()

methods(methods) ## no methods found methods(mean) ## [1] mean.Date mean.default mean.difftime ## [4] mean.POSIXct mean.POSIXlt ## see ‘?methods’ for accessing help and source code

The Big R-Book

Подняться наверх