So in S3, it is not the object that has to know how a call to it has to be handled, but it is the generic function 5 that gets the call and has to dispatch it.
The way this works in R is by calling UseMethod()
in the dispatching function. This creates a vector of function names, like
UseMethod()
paste0(“generic”, “.”, c(class(x), “default”))
and dispatches to the most specific handling function available. The default class is the last in the list and is the last resort: if R does not find a class specific method it will call the default action.
Beneath you can see this in action:
# probe # Dispatcher function # Arguments: # x -- account object # Returns # confirmation of object typeprobe <- function(x) UseMethod(“probe”) # probe.account # action for account object for dispatcher function probe() # Arguments: # x -- account object # Returns # confirmation of object “account”probe.account <- function(x) “This is a bank account” # probe.default # action if an incorrect object type is provided to probe() # Arguments: # x -- account object # Returns # error messageprobe.default <- function(x) “Sorry. Unknown class” probe( structure( list(), class = “account”)) ## [1] “This is a bank account” # No method for class ‘customer’, fallback to ‘account’ probe( structure( list(), class = c(“customer”, “account”))) ## [1] “This is a bank account” # No method for class ‘customer’, so falls back to default probe( structure( list(), class = “customer”)) ## [1] “Sorry. Unknown class” probe(df) # fallback to default for data.frame## [1] “Sorry. Unknown class” probe.account(df) # force R to use the account method## [1] “This is a bank account” my_curr_acc <- account(“Philippe”, 150) # real account probe(my_curr_acc) ## [1] “This is a bank account”
Note – Avoid direct calls
As you can see from the above, methods are normal R functions with a specific name. So, you might be tempted to call them directly (e.g. call directly print.data.frame()
when working with a data-frame) Actually, that is not such a good idea. This means that if, for example later you improve the dispatch method that this call will never see those improvements.
Hint – Speed gain
However, you might find that in some cases, there is a significant performance gain when skipping the dispatch method …well, in that case you might consider to bypass the dispatching and add a remark in the code to watch this instance. a
6.2.4 Group Generic Functions
It is possible to implement methods for multiple generic functions with one function via the mechanism of group generics. Group generic methods can be defined for four pre-specified groups of functions in R: “Math,” “Ops,” “Summary” and “Complex.” 6
The four “group generics” and the functions they include are:
1 Group Math: Members of this group dispatch on x. Most members accept only one argument, except log, round and signif that accept one or two arguments, while trunc accepts one or more. Members of this group are:abs, sign, sqrt, floor, ceiling, trunc, round, signifexp, log, expm1, log1p, cos, sin, tan, cospi, sinpi, tanpi, acos, asin, atan cosh, sinh, tanh, acosh, asinh, atanhlgamma, gamma, digamma, trigammacumsum, cumprod, cummax, cummin
2 Group Ops: This group contains both binary and unary operators ( +, - and !): when a unary operator is encountered, the Ops method is called with one argument and e2 is missing. The classes of both arguments are considered in dispatching any member of this group. For each argument, its vector of classes is examined to see if there is a matching specific (preferred) or Ops method. If a method is found for just one argument or the same method is found for both, it is used. If different methods are found, there is a warning about incompatible methods: in that case or if no method is found for either argument, the internal method is used. If the members of this group are called as functions, any argument names are removed to ensure that positional matching is always used.+, -, *, /, ∧, \%\%, \%/\%&, |, !==, !=, <, <=, >=, >
3 Group Summary: Members of this group dispatch on the first argument supplied.all, anysum, prodmin, maxrange
4 Group complex: Members of this group dispatch on z.Arg, Conj, Im, Mod, Re
Of course, a method defined for an individual member of the group takes precedence over a method defined for the group as a whole, because it is more specific.
Note – Distinguish groups and functions
Math
, Ops
, Summary
, and Complex
aren't functions themselves, but instead represent groups of functions. Also note that inside a group generic function a special variable .Generic
provides the actual generic function that is called.
If you have complex class hierarchies, it is sometimes useful to call the parent method . This parent method is the method that would have been called if the object-specific one does not exist. For example, if the object is savings_account
, which is a child of account
then calling the function with savings_account
will return the method associated to account
if there is no specific method and it will call the specific method if it exists.
Hint – Find what is the next method
More information can be found using ?NextMethod
.
The S4 system is very similar to the S3 system, but it adds a certain obligatory formalism. For example, it is necessary to define the class before using it. This adds some lines of code but the payoff is increased clarity.
In S4
1 classes have formal definitions that describe their data fields and inheritance structures (parent classes);
2 method dispatch is more flexible and can be based on multiple arguments to a generic function, not just one; and
3 there is a special operator, @, for extracting fields from an S4 object.
All the S4 related code is stored in the methods package.
Hint – Loading the library methods
While the methods
package is always available when running R interactively (like in RStudio or in the R terminal), it is not necessarily loaded when running R in batch mode. So, you might want to include an explicit library(methods)
statement in your code when using S4.
Читать дальше