Module # 7 R Object: S3 vs. S4 assignment
> # Module 7
>
> data("mtcars")
>
> cat("== STEP 1: DATA ==\n")
== STEP 1: DATA ==
> print(head(mtcars, 6))
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
>
> cat("\n== STEP 2: GENERIC FUNCTIONS CHECK ==\n")
== STEP 2: GENERIC FUNCTIONS CHECK ==
> cat("class(mtcars): ", paste(class(mtcars), collapse = ", "), "\n", sep = "")
class(mtcars): data.frame
> cat("typeof(mtcars): ", typeof(mtcars), "\n", sep = "")
typeof(mtcars): list
> cat("isS4(mtcars): ", isS4(mtcars), "\n", sep = "")
isS4(mtcars): FALSE
>
> cat("\nIs 'summary' an S3 standard generic? ", isS3stdGeneric("summary"), "\n", sep = "")
Is 'summary' an S3 standard generic? TRUE
> cat("Methods for 'summary':\n")
Methods for 'summary':
> print(methods("summary"))
[1] summary.aov summary.aovlist*
[3] summary.aspell* summary.car_data
[5] summary.check_packages_in_dir* summary.connection
[7] summary.data.frame summary.Date
[9] summary.default summary.ecdf*
[11] summary.factor summary.glm
[13] summary.infl* summary.lm
[15] summary.loess* summary.manova
[17] summary.matrix summary.mlm*
[19] summary.nls* summary.packageStatus*
[21] summary.POSIXct summary.POSIXlt
[23] summary.ppr* summary.prcomp*
[25] summary.princomp* summary.proc_time
[27] summary.rlang:::list_of_conditions* summary.rlang_error*
[29] summary.rlang_message* summary.rlang_trace*
[31] summary.rlang_warning* summary.srcfile
[33] summary.srcref summary.stepfun
[35] summary.stl* summary.table
[37] summary.tukeysmooth* summary.warnings
see '?methods' for accessing help and source code
> cat("\nsummary(mtcars):\n")
summary(mtcars):
> print(summary(mtcars))
mpg cyl disp hp drat
Min. :10.40 Min. :4.000 Min. : 71.1 Min. : 52.0 Min. :2.760
1st Qu.:15.43 1st Qu.:4.000 1st Qu.:120.8 1st Qu.: 96.5 1st Qu.:3.080
Median :19.20 Median :6.000 Median :196.3 Median :123.0 Median :3.695
Mean :20.09 Mean :6.188 Mean :230.7 Mean :146.7 Mean :3.597
3rd Qu.:22.80 3rd Qu.:8.000 3rd Qu.:326.0 3rd Qu.:180.0 3rd Qu.:3.920
Max. :33.90 Max. :8.000 Max. :472.0 Max. :335.0 Max. :4.930
wt qsec vs am gear
Min. :1.513 Min. :14.50 Min. :0.0000 Min. :0.0000 Min. :3.000
1st Qu.:2.581 1st Qu.:16.89 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:3.000
Median :3.325 Median :17.71 Median :0.0000 Median :0.0000 Median :4.000
Mean :3.217 Mean :17.85 Mean :0.4375 Mean :0.4062 Mean :3.688
3rd Qu.:3.610 3rd Qu.:18.90 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:4.000
Max. :5.424 Max. :22.90 Max. :1.0000 Max. :1.0000 Max. :5.000
carb
Min. :1.000
1st Qu.:2.000
Median :2.000
Mean :2.812
3rd Qu.:4.000
Max. :8.000
>
> cat("\n== BLOG QUESTIONS (QUICK OUTPUT) ==\n")
== BLOG QUESTIONS (QUICK OUTPUT) ==
> cat("OO system (S3 vs S4): use isS4(x); S3 typically isS4(x)=FALSE and has class().\n")
OO system (S3 vs S4): use isS4(x); S3 typically isS4(x)=FALSE and has class().
> cat("Base type: typeof(x) (plus str(x) for structure).\n")
Base type: typeof(x) (plus str(x) for structure).
> cat("Generic function: dispatches methods based on class (e.g., summary(), print()).\n")
Generic function: dispatches methods based on class (e.g., summary(), print()).
> cat("S3 vs S4: S3 is informal (class tag); S4 is formal (setClass, slots, type checking).\n")
S3 vs S4: S3 is informal (class tag); S4 is formal (setClass, slots, type checking).
>
> cat("\n== STEP 3: S3 EXAMPLE ==\n")
== STEP 3: S3 EXAMPLE ==
> mycars <- list(data = mtcars, source = "datasets::mtcars")
> class(mycars) <- "car_data"
>
> print.car_data <- function(x, ...) {
+ cat("S3 'car_data' | source:", x$source,
+ "| dims:", nrow(x$data), "x", ncol(x$data), "\n")
+ invisible(x)
+ }
>
> summary.car_data <- function(object, ...) {
+ out <- list(
+ source = object$source,
+ dims = dim(object$data),
+ numeric_summary = summary(object$data)
+ )
+ class(out) <- "summary.car_data"
+ out
+ }
>
> print.summary.car_data <- function(x, ...) {
+ cat("Summary for S3 'car_data'\n")
+ cat("source:", x$source, "\n")
+ cat("dims:", x$dims[1], "x", x$dims[2], "\n\n")
+ print(x$numeric_summary)
+ invisible(x)
+ }
>
> print(mycars)
S3 'car_data' | source: datasets::mtcars | dims: 32 x 11
> print(summary(mycars))
Summary for S3 'car_data'
source: datasets::mtcars
dims: 32 x 11
mpg cyl disp hp drat
Min. :10.40 Min. :4.000 Min. : 71.1 Min. : 52.0 Min. :2.760
1st Qu.:15.43 1st Qu.:4.000 1st Qu.:120.8 1st Qu.: 96.5 1st Qu.:3.080
Median :19.20 Median :6.000 Median :196.3 Median :123.0 Median :3.695
Mean :20.09 Mean :6.188 Mean :230.7 Mean :146.7 Mean :3.597
3rd Qu.:22.80 3rd Qu.:8.000 3rd Qu.:326.0 3rd Qu.:180.0 3rd Qu.:3.920
Max. :33.90 Max. :8.000 Max. :472.0 Max. :335.0 Max. :4.930
wt qsec vs am gear
Min. :1.513 Min. :14.50 Min. :0.0000 Min. :0.0000 Min. :3.000
1st Qu.:2.581 1st Qu.:16.89 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:3.000
Median :3.325 Median :17.71 Median :0.0000 Median :0.0000 Median :4.000
Mean :3.217 Mean :17.85 Mean :0.4375 Mean :0.4062 Mean :3.688
3rd Qu.:3.610 3rd Qu.:18.90 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:4.000
Max. :5.424 Max. :22.90 Max. :1.0000 Max. :1.0000 Max. :5.000
carb
Min. :1.000
1st Qu.:2.000
Median :2.000
Mean :2.812
3rd Qu.:4.000
Max. :8.000
> cat("isS4(mycars): ", isS4(mycars), "\n", sep = "")
isS4(mycars): FALSE
> cat("typeof(mycars): ", typeof(mycars), "\n", sep = "")
typeof(mycars): list
> cat("class(mycars): ", paste(class(mycars), collapse = ", "), "\n", sep = "")
class(mycars): car_data
>
> cat("\n== STEP 3: S4 EXAMPLE ==\n")
== STEP 3: S4 EXAMPLE ==
> setClass(
+ "CarData",
+ slots = c(
+ data = "data.frame",
+ source = "character"
+ )
+ )
>
> setMethod("show", "CarData", function(object) {
+ cat("An object of class 'CarData'\n")
+ cat("source:", object@source, "\n")
+ cat("dims:", nrow(object@data), "x", ncol(object@data), "\n")
+ })
>
> mycars4 <- new("CarData", data = mtcars, source = "datasets::mtcars")
> mycars4
An object of class 'CarData'
source: datasets::mtcars
dims: 32 x 11
> cat("isS4(mycars4): ", isS4(mycars4), "\n", sep = "")
isS4(mycars4): TRUE
> cat("typeof(mycars4): ", typeof(mycars4), "\n", sep = "")
typeof(mycars4): S4
> cat("class(mycars4): ", paste(class(mycars4), collapse = ", "), "\n", sep = "")
class(mycars4): CarData
>
> cat("\n== EXTRA: HOW TO TELL SYSTEM + TYPE ==\n")
== EXTRA: HOW TO TELL SYSTEM + TYPE ==
> check_obj <- function(x, name = "object") {
+ cat("\n--", name, "--\n")
+ cat("isS4:", isS4(x), "\n")
+ cat("class:", paste(class(x), collapse = ", "), "\n")
+ cat("typeof:", typeof(x), "\n")
+ cat("str:\n")
+ str(x)
+ }
>
> check_obj(mtcars, "mtcars")
-- mtcars --
isS4: FALSE
class: data.frame
typeof: list
str:
'data.frame': 32 obs. of 11 variables:
$ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
$ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
$ disp: num 160 160 108 258 360 ...
$ hp : num 110 110 93 110 175 105 245 62 95 123 ...
$ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
$ wt : num 2.62 2.88 2.32 3.21 3.44 ...
$ qsec: num 16.5 17 18.6 19.4 17 ...
$ vs : num 0 0 1 1 0 1 0 1 1 1 ...
$ am : num 1 1 1 0 0 0 0 0 0 0 ...
$ gear: num 4 4 4 3 3 3 3 4 4 4 ...
$ carb: num 4 4 1 1 2 1 4 2 2 4 ...
> check_obj(mycars, "mycars (S3)")
-- mycars (S3) --
isS4: FALSE
class: car_data
typeof: list
str:
List of 2
$ data :'data.frame': 32 obs. of 11 variables:
..$ mpg : num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
..$ cyl : num [1:32] 6 6 4 6 8 6 8 4 4 6 ...
..$ disp: num [1:32] 160 160 108 258 360 ...
..$ hp : num [1:32] 110 110 93 110 175 105 245 62 95 123 ...
..$ drat: num [1:32] 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
..$ wt : num [1:32] 2.62 2.88 2.32 3.21 3.44 ...
..$ qsec: num [1:32] 16.5 17 18.6 19.4 17 ...
..$ vs : num [1:32] 0 0 1 1 0 1 0 1 1 1 ...
..$ am : num [1:32] 1 1 1 0 0 0 0 0 0 0 ...
..$ gear: num [1:32] 4 4 4 3 3 3 3 4 4 4 ...
..$ carb: num [1:32] 4 4 1 1 2 1 4 2 2 4 ...
$ source: chr "datasets::mtcars"
- attr(*, "class")= chr "car_data"
> check_obj(mycars4, "mycars4 (S4)")
-- mycars4 (S4) --
isS4: TRUE
class: CarData
typeof: S4
str:
Formal class 'CarData' [package ".GlobalEnv"] with 2 slots
..@ data :'data.frame': 32 obs. of 11 variables:
.. ..$ mpg : num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
.. ..$ cyl : num [1:32] 6 6 4 6 8 6 8 4 4 6 ...
.. ..$ disp: num [1:32] 160 160 108 258 360 ...
.. ..$ hp : num [1:32] 110 110 93 110 175 105 245 62 95 123 ...
.. ..$ drat: num [1:32] 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
.. ..$ wt : num [1:32] 2.62 2.88 2.32 3.21 3.44 ...
.. ..$ qsec: num [1:32] 16.5 17 18.6 19.4 17 ...
.. ..$ vs : num [1:32] 0 0 1 1 0 1 0 1 1 1 ...
.. ..$ am : num [1:32] 1 1 1 0 0 0 0 0 0 0 ...
.. ..$ gear: num [1:32] 4 4 4 3 3 3 3 4 4 4 ...
.. ..$ carb: num [1:32] 4 4 1 1 2 1 4 2 2 4 ...
..@ source: chr "datasets::mtcars" In this module, I explored R’s object-oriented systems S3 and S4 using the mtcars dataset. To determine which OO system an object belongs to, I used class and isS4. If isS4 returns TRUE, the object is S4. If it returns FALSE and the object has a class attribute, it is typically S3.
To determine the base type of an object, I used typeof, which reveals the underlying storage type. For example, mtcars is internally stored as a list even though its class is data frame. A generic function in R performs method dispatch based on an object’s class. Functions such as summary, print, and plot behave differently depending on the object they receive. The main difference between S3 and S4 is that S3 is informal and flexible, relying on class attributes and naming conventions, while S4 is formal and structured, requiring explicit class definitions, defined slots, and stronger type checking.
Comments
Post a Comment