# 3 Coin Objects

## 3.1 Introduction

In this chapter we describe how to create object classes in R. Specifically, we will focus on the so-called S3 classes or S3 system. This is one of the three types of Object Oriented (OO) systems available in R, and it is the most common among R packages.

## 3.2 Objects and Classes

In the previous chapter we learned how to create a `toss()` function, and also how to document it with roxygen comments. We can invoke `toss()` to generate a first series of five tosses, and then compute the proportion of heads:

``````# random seed
set.seed(534)

# five tosses
five <- toss(coin, times = 5)
five

# proportion of heads in five
#> [1] 0.6``````

We can also get a second series of tosses, but this time involving tossing a coin six times. Similarly, we compute the proportion of heads:

``````# six tosses
six <- toss(coin, times = 6)
six

# prop of heads in six
#> [1] 0.8``````

The above code works … except that there is an error; the number of heads in `six` is being divided by 5 instead of 6. R hasn’t detected this error: it doesn’t know that the division has to be done using `length(six)`.

Wouldn’t it be prefarable to have some mechanism that prevented this type of error from happening? Bugs will always be part of any programming activity, but it is better to minimize certain types of errors like the one above.

## 3.3 S3 Classes

R has two (plus one) object oriented systems, so it can be a bit intimidatin gwhen you read and learn about them for the first time. The goal of this tutorial is not to make you an expert in all R’s OO systems, but to help you become familiar with the so-called S3 class.

S3 implements a style of object oriented programming called generic-function OO. S3 uses a special type of function called a generic function that decides which method to call. Keep in mind that S3 is a very casual system: it does not really have a formal definition of classes.

S3 classes are widely-used, in particular for statistical models in the `"stats"` package. S3 classes are very informal in that there is not a formal definition for an S3 class. Usually, S3 objects are built on top of lists, or atomic vectors with attributes. But you can also turn functions into S3 objects.

Note that in more formal OOP languages, all functions are associated with a class, while in R, only some are.

### 3.3.1 Making an object

To make an object an instance of a class, you just take an existing base object and set the `"class"` attribute. You can do that during creation of the object with `structure()`

``````# object coin via structure()
coin1 <- structure(c("heads", "tails"), class = "coin")
coin1
#> attr(,"class")
#> [1] "coin"``````

You can also create an object first, and then specify its class with the function `class()`:

``````# object coin via class()
class(coin2) <- "coin"
coin2
#> attr(,"class")
#> [1] "coin"``````

As any object in R, you can inspect the class `coin1`, and `coin2` with the `class()` function:

``````class(coin1)
#> [1] "coin"

class(coin2)
#> [1] "coin"``````

You can also determine if an object inherits from a specific class using `inherits()`

``````inherits(coin2, "coin")
#> [1] TRUE``````

Having a `"coin"` object, we can pass it to the `toss()` function to simulate flipping the coin:

``````toss(coin1, times = 5)

## 3.4 A more robust `"coin"` class

Let’s review our class `"coin"`. The way we defined a coin object was like this:

``````# object coin
class(coin1) <- "coin" ``````

While this definition is good to illustrate the concept of an object, its class, and how to define generic methods, it is a very loose-defined class. One could create a `"coin"` out of `c('tic', 'tac', 'toe')`, and then use `toss()` on it:

``````ttt <- c('tic', 'tac', 'toe')
class(ttt) <- "coin"

toss(ttt)
#> [1] "tic"``````

We need a more formal definition of a coin. For instance, it makes more sense to require that a coin should only have two sides. In this way, the vector `ttt` would not be a valid coin.

For convenience purposes, we can define a class constructor function to initialize a `"coin"` object:

``````# constructor function (version 1)
coin <- function(object = c("heads", "tails")) {
class(object) <- "coin"
object
}

# default coin
coin()
#> attr(,"class")
#> [1] "coin"

# another coin
coin(c("h", "t"))
#> [1] "h" "t"
#> attr(,"class")
#> [1] "coin"``````

## 3.5 Improving `"coin"` objects

To implement the requirement that a coin must have two sides, we can add an if condition to check for the length of the input vector:

``````# constructor function (version 2)
coin <- function(object = c("heads", "tails")) {
if (length(object) != 2) {
stop("\n'object' must be of length 2")
}
class(object) <- "coin"
object
}``````

Let’s try our modified constructor function `coin()` to create a virtual version of the US penny like the one in the image below:

``````# US penny
penny <- coin(c("lincoln", "shield"))
penny
#> [1] "lincoln" "shield"
#> attr(,"class")
#> [1] "coin"``````

Now let’s try `coin()` with an invalid input vector. In this case, the constructor function will `stop()` execution with an error message because the input argument has more than 2 elements.

``````# invalid coin
ttt <- c('tic', 'tac', 'toe')
coin(ttt)
#> Error in coin(ttt):
#> 'object' must be of length 2``````

Because the `toss()` function simulates flips using `sample()`, we can take advantage of the argument `prob` to specify probabilities for each side of the coin. In this way, we can create loaded (i.e. biased) coins.

The way we are going to keep the probability of each side of the coin is with the use an objetc’s attributes. An example of an attribute is the class of an object. For example the class of our `"coin"` objects:

``````penny
#> [1] "lincoln" "shield"
#> attr(,"class")
#> [1] "coin"``````

Notice how everytime you print the name of a `"coin"` object, its class is displayed in the form of `attr(,"class")`.

### 3.5.1 Attributes

In addition to the class attribute of a coin, the idea is to assign another attribute for the probability values. We can do this by adding a `prob` argument to the constructor function, and then pass it as an attribute of the coin object inside the class-constructor function.

``````# constructor function (version 3)
coin <- function(object = c("heads", "tails"), prob = c(0.5, 0.5)) {
if (length(object) != 2) {
stop("\n'object' must be of length 2")
}
attr(object, "prob") <- prob
class(object) <- "coin"
return(object)
}

coin()
#> attr(,"prob")
#> [1] 0.5 0.5
#> attr(,"class")
#> [1] "coin"``````

In the previous code, the `prob` argument takes a vector of probabilities for each element in `object`. This vector is passed to `object` via the function `attr()` inside the body of `coin()`. Notice the use of a default `prob = c(0.5, 0.5)`, that is, a fair coin by default.

### 3.5.2 Using a list

Another way to implement a constructor function `coin()` that returns an object containing values for both the sides and the probabilities, is to use an R list. Here’s the code for this option:

``````# constructor function (version 4)
coin <- function(sides = c("heads", "tails"), prob = c(0.5, 0.5)) {
if (length(sides) != 2) {
stop("\n'sides' must be of length 2")
}
res <- list(sides = sides, prob = prob)
class(res) <- "coin"
return(res)
}

coin()
#> \$sides
#>
#> \$prob
#> [1] 0.5 0.5
#>
#> attr(,"class")
#> [1] "coin"``````

### 3.5.3 Auxiliary Checker

Once again, we need to check for the validity of `prob`. We basically need to check that `prob` and its elements meet the following requirements:

• must be numeric and of length 2
• probability values must be between 0 and 1
• the sum of these values must add up to 1

Here is one possible function to check the aspects of `prob` listed above:

``````check_prob <- function(prob) {
if (length(prob) != 2 | !is.numeric(prob)) {
stop("\n'prob' must be a numeric vector of length 2")
}
if (any(prob < 0) | any(prob > 1)) {
stop("\n'prob' values must be between 0 and 1")
}
if (sum(prob) != 1) {
stop("\nelements in 'prob' must add up to 1")
}
TRUE
}``````

Note that I’m adding a `TRUE` statement at the end of the function. This is just an auxiliary value to know if the function returns a valid `prob`. Now let’s test it with valid and invalid values:

``````# Valid -----------------------
check_prob(c(0.5, 0.5))
#> [1] TRUE
check_prob(c(0.1, 0.9))
#> [1] TRUE
check_prob(c(1/3, 2/3))
#> [1] TRUE
check_prob(c(1/3, 6/9))
#> [1] TRUE``````
``````# Invalid -----------------------
check_prob(1)
#> Error in check_prob(1):
#> 'prob' must be a numeric vector of length 2
check_prob(c(0.1, 0.2, 0.3))
#> Error in check_prob(c(0.1, 0.2, 0.3)):
#> 'prob' must be a numeric vector of length 2
# negative probability
check_prob(c(-0.2, 0.8))
#> Error in check_prob(c(-0.2, 0.8)):
#> 'prob' values must be between 0 and 1
# what should we do in this case?
check_prob(c(0.33, 0.66))
#> Error in check_prob(c(0.33, 0.66)):
#> elements in 'prob' must add up to 1``````

Here’s the improved constructor function `coin()`:

``````# constructor function (version 5)
coin <- function(sides = c("heads", "tails"), prob = c(0.5, 0.5)) {
if (length(sides) != 2) {
stop("\n'sides' must be of length 2")
}
check_prob(prob)
res <- list(sides = sides, prob = prob)
class(res) <- "coin"
return(res)
}

coin1 <- coin()
coin1
#> \$sides
#>
#> \$prob
#> [1] 0.5 0.5
#>
#> attr(,"class")
#> [1] "coin"``````

## 3.7 Extending classes

We can extend the class `"coin"` and create a derived class for special types of coins. For instance, say we want to create a class `"quarter"`. One side of the coin refers to George Washington, while the other side refers to the bald eagle:

https://en.wikipedia.org/wiki/Quarter_(United_States_coin)

We can create a quarter by first starting with a `coin()` of `sides` washington and bald-eagle, and then assign a `"quarter"` class:

``````quarter1 <- coin(c("washington", "bald-eagle"))
class(quarter1) <- c("quarter", "coin")
quarter1
#> object "coin"
#>
#>         side prob
#> 1 washington  0.5
#> 2 bald-eagle  0.5``````

Interestingly, our coin `quarter1` inherits from `"coin"`:

``````inherits(quarter1, "coin")
#> [1] TRUE``````

In other words, `quartier1` is of class `"quarter"` but it is also a `"coin"` object.

Likewise, we can create a class for a slightly unbalanced `"dime"`:

``````dime1 <- coin(c("roosevelt", "torch"), prob = c(0.48, 0.52))
class(dime1) <- c("dime", "coin")
dime1
#> object "coin"
#>
#>        side prob
#> 1 roosevelt 0.48
#> 2     torch 0.52``````

Here’s another coin example, a peso, from Mexico (where I grew up). When you flip a peso, mexicans will talk about two sides: aguila (eagle) or sol (sun):

``````peso <- coin(c("aguila", "sol"))
class(peso) <- c("peso", "coin")
peso
#> object "coin"
#>
#>     side prob
#> 1 aguila  0.5
#> 2    sol  0.5``````

#### Make a donation

If you find this resource useful, please consider making a one-time donation in any amount. Your support really matters.