John Chambers, creator of S programming language
#> R version 4.5.1 (2025-06-13)
#> Platform: aarch64-apple-darwin20
#> Running under: macOS Sequoia 15.7.1
#>
#> Matrix products: default
#> BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
#>
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#>
#> time zone: Europe/London
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] DiagrammeR_1.0.11
#>
#> loaded via a namespace (and not attached):
#> [1] digest_0.6.37 RColorBrewer_1.1-3 fastmap_1.2.0 xfun_0.53
#> [5] magrittr_2.0.4 glue_1.8.0 knitr_1.50 htmltools_0.5.8.1
#> [9] rmarkdown_2.30 cli_3.6.5 visNetwork_2.1.4 compiler_4.5.1
#> [13] tools_4.5.1 evaluate_1.0.5 yaml_2.3.10 rlang_1.1.6
#> [17] jsonlite_2.0.0 htmlwidgets_1.6.4
Function has a single interface (outside), but contains (inside) several class-specific implementations.
# imagine a function with object x as an argument
# from the outside, users interact with the same function
# but inside the function, there are provisions to deal with objects of different classes
some_function <- function(x) {
if is.numeric(x) {
# implementation for numeric x
} else if is.character(x) {
# implementation for character x
} ...
}#> species island bill_length_mm bill_depth_mm
#> Adelie :152 Biscoe :168 Min. :32.10 Min. :13.10
#> Chinstrap: 68 Dream :124 1st Qu.:39.23 1st Qu.:15.60
#> Gentoo :124 Torgersen: 52 Median :44.45 Median :17.30
#> Mean :43.92 Mean :17.15
#> 3rd Qu.:48.50 3rd Qu.:18.70
#> Max. :59.60 Max. :21.50
#> NA's :2 NA's :2
#>
#> Call:
#> lm(formula = mpg ~ hp, data = mtcars)
#>
#> Residuals:
#> Min 1Q Median 3Q Max
#> -5.7121 -2.1122 -0.8854 1.5819 8.2360
#>
#> Coefficients:
#> Estimate Std. Error t value Pr(>|t|)
#> (Intercept) 30.09886 1.63392 18.421 < 2e-16 ***
#> hp -0.06823 0.01012 -6.742 1.79e-07 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> Residual standard error: 3.863 on 30 degrees of freedom
#> Multiple R-squared: 0.6024, Adjusted R-squared: 0.5892
#> F-statistic: 45.46 on 1 and 30 DF, p-value: 1.788e-07
A class defines what an object is and methods describe what that object can do.
1. Encapsulated OOP
object.method(arg1, arg2)object.method(arg1, arg2)object, apply method for object’s class with arguments arg1 and arg22. Functional OOP
generic(object, arg2, arg3)Bioconductorggplot2 >= v4.0.0ggplot2 < v4.0.0.sloop::otype to determine OOP systembase objects and OO objects are different subsets of objects
base::is.object(): TRUE/FALSE for OOPsloop::otype(): gives object type: "base", "S3", etc.class()class() gives misleading results for base objects.
It is not enough to call class() on an object to determine if it is base or OO, as this will return the implicit class (rather than NULL) when there is no class attribute (i.e. "matrix", "array", "function", "numeric" or result of typeof()):
sloop::s3_class() is safer, as it returns the implicit class that the S3 and S4 systems will use to pick methods
Only OO objects have a “class” attribute, but every object–whether base or OO–has a base type
There are 25 types.
They are most important in C code, so often see them called by their C type names, e.g. NILSXP for NULL.
Base types in R
The graph above was made with SankeyMATIC
// toggle "Show Values"
// set Default Flow Colors from "each flow's Source"
base\ntypes [8] vectors
base\ntypes [3] functions
base\ntypes [1] environments
base\ntypes [1] S4 OOP
base\ntypes [3] language\ncomponents
base\ntypes [6] C components
vectors [1] NULL
vectors [1] logical
vectors [1] integer
vectors [1] double
vectors [1] complex
vectors [1] character
vectors [1] list
vectors [1] raw
functions [1] closure
functions [1] special
functions [1] builtin
environments [1] environment
S4 OOP [1] S4
language\ncomponents [1] symbol
language\ncomponents [1] language
language\ncomponents [1] pairlist
C components [1] externalptr
C components [1] weakref
C components [1] bytecode
C components [1] promise
C components [1] ...
C components [1] any
R uses “numeric” to mean three slightly different things:
Alias for double
In S3 and S4, as shorthand for integer or double
is.numeric() tests for objects that behave like numbers
Advanced R consistently uses numeric to mean an object of type integer or double.
“numeric” is taken as either integer or double, and used when choosing methods: