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

Popular posts from this blog

Module # 4 Programming structure assignment

Assignment #10: Building Your Own R Package

Module # 8 Input/Output, string manipulation and plyr package