0% found this document useful (0 votes)
9 views14 pages

Mastering S3 Methods in R Tutorial

The document is a comprehensive tutorial on S3 methods in R, detailing the structure and functionality of S3 objects, generics, and methods. It provides examples of creating custom generics and methods, handling multiple inheritance, and extending base generics. Additionally, it covers best practices, debugging techniques, and includes a live demo plan along with exercises for further learning.

Uploaded by

Ram Gaduputi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views14 pages

Mastering S3 Methods in R Tutorial

The document is a comprehensive tutorial on S3 methods in R, detailing the structure and functionality of S3 objects, generics, and methods. It provides examples of creating custom generics and methods, handling multiple inheritance, and extending base generics. Additionally, it covers best practices, debugging techniques, and includes a live demo plan along with exercises for further learning.

Uploaded by

Ram Gaduputi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd

S3 Methods in R — From Zero to

Expert
A complete, hands-on video tutorial
(with code & slides)
What is S3? (the 60‑second gist)
• Object = regular R object + class attribute (e.g., class(x) <- "person")
• Generic = function that dispatches: UseMethod("generic")
• Method = function named [Link] (e.g., [Link])
• S3 is dynamic and informal
– No formal class schema
– Easy to extend at runtime
Minimal example: a custom
generic + method
greet <- function(x, ...) UseMethod("greet")

[Link] <- function(x, ...) "Hello!"

[Link] <- function(x, ...) {


sprintf("Hello, %s (%d)!", x$name, x$age)
}

p <- list(name = "Alice", age = 34); class(p) <- "person"


greet(p) # -> "Hello, Alice (34)!"
greet(1) # -> "Hello!"
How dispatch works
• S3 usually dispatches on the class of the first argument
• Multiple inheritance via class(x) <- c("child","parent")
– Lookup order: [Link] → [Link] →
[Link]
• Helpful tools
– methods("greet")
– utils::getS3method("greet","person")
Constructor + print + summary
methods
new_person <- function(name, age) {
stopifnot([Link](name), length(name) == 1,
[Link](age), length(age) == 1, age >= 0)
structure(list(name = name, age = [Link](age)), class =
"person")
}

[Link] <- function(x, ...) {


cat(sprintf("person{name=%s, age=%d}\n", x$name, x$age))
invisible(x)
}

[Link] <- function(object, ...) {


out <- list(name = object$name, is_adult = object$age >=
18L)
class(out) <- "[Link]"
out
}

[Link] <- function(x, ...) {


cat("Summary(person)\n name:", x$name, "\n isAdult:",
Multiple inheritance +
NextMethod()
new_employee <- function(name, age, title) {
x <- list(name = name, age = [Link](age), title = title)
class(x) <- c("employee", "person")
x
}

[Link] <- function(x, ...) {


cat(sprintf("employee<title=%s>\n", x$title))
NextMethod() # calls [Link]
}
Extending base generics
(format/[Link]/plot)
[Link] <- function(x, ...) sprintf("%s (%d)",
x$name, x$age)
[Link] <- function(x, ...) sprintf("Person<%s,
%d>", x$name, x$age)

[Link] <- function(x, ...) {


plot(x$age, 1, xlab = "age", ylab = "", yaxt = "n", main =
x$name, ...)
points(x$age, 1, pch = 19)
}
Group generics: Ops / Math /
Summary
new_numwrap <- function(x) structure(list(x = [Link](x)),
class = "numwrap")

[Link] <- function(e1, e2) {


op <- .Generic
if (inherits(e1, "numwrap") && inherits(e2, "numwrap"))
return(new_numwrap([Link](op, list(e1$x, e2%x))))
if (inherits(e1, "numwrap") && [Link](e2))
return(new_numwrap([Link](op, list(e1$x, e2))))
if ([Link](e1) && inherits(e2, "numwrap"))
return(new_numwrap([Link](op, list(e1, e2$x))))
stop(sprintf("Operation '%s' not supported for these
types.", op))
}

[Link] <- function(x, ...) {


op <- .Generic
new_numwrap([Link](op, list(x$x)))
}

[Link] <- function(..., [Link] = FALSE) {


Inspecting & debugging S3
methods
• List methods for a generic
– methods("print"), methods("summary")
• Find a specific method object
– utils::getS3method("summary","lm")
• See where it’s defined
– getAnywhere("[Link]")
• Debug/trace without editing
– debugonce([Link])
– trace("[Link]", tracer = quote(cat("->
entering\n")))
Packaging & registration (roxygen2)
#' @export
greet <- function(x, ...) UseMethod("greet")

#' @exportS3Method greet person


[Link] <- function(x, ...) sprintf("Hi, %s!", x$name)

#' @exportS3Method print person


[Link] <- function(x, ...) { cat(x$name, "\n");
invisible(x) }
CDISC-flavored example: adsl_tbl
wrapper
new_adsl_tbl <- function(df, studyid) {
stopifnot([Link](df))
structure(df, class = c("adsl_tbl", class(df)), studyid =
studyid)
}

print.adsl_tbl <- function(x, ...) {


cat("adsl_tbl<studyid=", attr(x, "studyid"), ">\n", sep =
"")
cat("Rows:", nrow(x), " Cols:", ncol(x), "\n")
if ("TRT01P" %in% names(x)) {
cat("TRT01P counts:\n"); print(table(x$TRT01P, useNA =
"ifany"))
}
invisible(x)
}

summary.adsl_tbl <- function(object, ...) {


out <- list(
studyid = attr(object, "studyid"),
n = nrow(object),
Best practices & common pitfalls
• Name methods exactly [Link]
– Avoid typos & mismatched signatures
• Keep methods compatible with the generic
– Include ... for forward compatibility
• Don’t redefine base generics
– Only implement methods for them
• Prefer inherits(x, "cls") over class(x) == "cls"
– It respects multiple inheritance
• When packaging
– Export the generic; register methods
(@exportS3Method)
Live demo plan (recording guide)
• Segment 1 (2 min): Intro & S3 idea
– Show class attribute & UseMethod
• Segment 2 (4 min): Constructor/print/summary
– Create and inspect person objects in RStudio
• Segment 3 (4 min): Inheritance + NextMethod
– employee extends person
• Segment 4 (5 min): Base & group generics
– [Link], plot, Ops/Math examples
• Segment 5 (3 min): Packaging + pitfalls
– Show roxygen tags; methods() checks
Exercises & next steps
• Implement score() generic + methods for person/employee
• Add [.person to access fields safely (optional)
• Wrap a tibble into adsl_tbl and extend print/summary for your study
• Package it: add roxygen tags, build, install, test with methods()

You might also like