# Functions as Objects, Environments and S3/R6 Classes — R Programming

Source: https://www.geekswithgeeks.com/en/r-programming/a-oop

> Understand environments, closures and R's object systems.

## How R organises objects

Every function has an **environment**: names are looked up in the function's own environment, then in the environment where the function was **defined**, then outwards to the global environment and loaded packages. This **lexical scoping** enables **closures**, functions that remember variables from where they were created, such as a counter factory. R has several object-oriented systems. **S3** is the simplest and most common: an object is usually a list with a **class attribute**, and **generic functions** such as `print()`, `summary()` and `plot()` dispatch to methods named `generic.class` (for example `print.invoice`). That is why `summary()` works differently on a data frame and on an `lm` model. **S4** adds formal class definitions and validity checks, used heavily in Bioconductor. **R6** (a package) provides classic mutable objects with methods and fields, useful for things with state such as a database connection pool or a simulation; R6 objects use **reference semantics**, unlike R's usual copy-on-modify values. Most analysis code needs only functions and data frames; S3 is worth knowing to read and extend packages.

## An S3 class with methods, and an R6 counter

S3 dispatch through generics; R6 objects are mutable references.

```r
new_invoice <- function(id, items, prices) {
  stopifnot(length(items) == length(prices))
  structure(list(id = id, items = items, prices = prices), class = "invoice")
}

print.invoice <- function(x, ...) {
  cat("Invoice", x$id, "with", length(x$items), "items, total Rs",
      format(sum(x$prices), big.mark = ","), "\n")
  invisible(x)
}

summary.invoice <- function(object, ...) {
  data.frame(item = object$items, price = object$prices)
}

inv <- new_invoice("INV-7", c("pen", "notebook"), c(49.5, 1200))
inv                 # calls print.invoice automatically
summary(inv)

Counter <- R6::R6Class("Counter",
  public = list(
    count = 0,
    add = function(n = 1) { self$count <- self$count + n; invisible(self) }
  )
)
c1 <- Counter$new()
c1$add()$add(5)     # method chaining
c1$count            # 6
```

## Generic job titles

An S3 generic is a job title like "print". When an invoice asks to be printed, R looks for the invoice-specific way of doing that job; if there is none, it falls back to the default way.

**Quiz:** How does S3 method dispatch decide which function to call for print(x)?

- [ ] It always calls print.default
- [ ] It uses the first argument's length
- [ ] S3 does not support dispatch
- [x] It looks for print.<class of x>, falling back to print.default

*Answer:* It looks for print.<class of x>, falling back to print.default. S3 generics dispatch on the class attribute to methods named generic.class.
