13.4 Generics and methods

Generic functions:

  • Consist of a call to UseMethod()
  • Pass arguments from the generic to the dispatched method “auto-magically”
my_new_generic <- function(x) {
  UseMethod("my_new_generic")
}

13.4.1 Method dispatch

  • UseMethod() creates a vector of method names
  • Dispatch
    • Examines all methods in the vector
    • Selects a method
x <- Sys.Date()
sloop::s3_dispatch(print(x))
#> => print.Date
#>  * print.default

13.4.2 Finding methods

While sloop::s3_dispatch() gives the specific method selected for a specific call, on can see the methods defined:

  • For a generic
sloop::s3_methods_generic("mean")
#> # A tibble: 9 × 4
#>   generic class      visible source             
#>   <chr>   <chr>      <lgl>   <chr>              
#> 1 mean    bench_time FALSE   registered S3method
#> 2 mean    Date       TRUE    base               
#> 3 mean    default    TRUE    base               
#> 4 mean    difftime   TRUE    base               
#> 5 mean    integer64  FALSE   registered S3method
#> 6 mean    POSIXct    TRUE    base               
#> 7 mean    POSIXlt    TRUE    base               
#> 8 mean    quosure    FALSE   registered S3method
#> 9 mean    vctrs_vctr FALSE   registered S3method
  • For a class
sloop::s3_methods_class("ordered")
#> # A tibble: 6 × 4
#>   generic       class   visible source             
#>   <chr>         <chr>   <lgl>   <chr>              
#> 1 as.data.frame ordered TRUE    base               
#> 2 Ops           ordered TRUE    base               
#> 3 relevel       ordered FALSE   registered S3method
#> 4 scale_type    ordered FALSE   registered S3method
#> 5 Summary       ordered TRUE    base               
#> 6 type_sum      ordered FALSE   registered S3method

13.4.3 Creating methods

Two rules:

  • Only write a method if you own the generic. Otherwise, bad manners.
  • Method must have same arguments as its generic–with one important exception: ...

Example from text:

I thought it would be good for us to work through this problem.

Carefully read the documentation for UseMethod() and explain why the following code returns the results that it does. What two usual rules of function evaluation does UseMethod() violate?

g <- function(x) {
  x <- 10
  y <- 10
  UseMethod("g")
}
g.default <- function(x) c(x = x, y = y)

x <- 1
y <- 1
g(x)
#> x y 
#> 1 1
g.default(x)
#> x y 
#> 1 1

Examples caught in the wild: