Handling errors

Your function works well, but what would happen if the wrong arguments were passed? Let’s check what happens with our function calculate_mean.

result <- calculate_mean(c("cat", "dog", "horse"))
Error in total + value: non-numeric argument to binary operator

This isn’t very descriptive or helpful. Fortunately, you can control how R will behave in an error condition by using stop or warning.

You use stop if you want to stop the function from continuing, and to print an error message for the user. For example, we could use is.numeric function to check if all of the values are numeric. If not, then we could call stop.

calculate_mean <- function(values){
     total <- 0.0
     count <- 0
     for (value in values){
         if (!is.numeric(value)){
             stop("Cannot calculate average of non-numeric values")
         }
         total <- total + value
         count <- count + 1
     }
     return(total / count)
}

result <- calculate_mean(c("cat", "dog", "horse"))
Error in calculate_mean(c("cat", "dog", "horse")): Cannot calculate average of non-numeric values

This is a much more useful error message! However, what if instead of stopping, we want to calculate the average of any numeric values, and just warn the user if non-numeric values are passed? We can do this using the warning function:

calculate_mean <- function(values){
     total <- 0.0
     count <- 0
     for (value in values){
         number <- as.numeric(value)

         if (!is.na(number)){
             total <- total + number
             count <- count + 1
         } else {
             warning("Skipping '", value, 
                     "' as it is not numeric")
         }
     }
     return(total / count)
}

result <- calculate_mean(c("cat", "dog", "horse"))
Warning in calculate_mean(c("cat", "dog", "horse")): NAs introduced by coercion
Warning in calculate_mean(c("cat", "dog", "horse")): Skipping 'cat' as it is
not numeric
Warning in calculate_mean(c("cat", "dog", "horse")): NAs introduced by coercion
Warning in calculate_mean(c("cat", "dog", "horse")): Skipping 'dog' as it is
not numeric
Warning in calculate_mean(c("cat", "dog", "horse")): NAs introduced by coercion
Warning in calculate_mean(c("cat", "dog", "horse")): Skipping 'horse' as it is
not numeric

In this case, we try to convert the value into a number using the as.numeric function. If this fails, it will return NA. We then test for NA using the is.na function, printing a warning that we are skipping this value if it isn’t a number.

Exercise

Add error handling to your calculate_max function so that it warns when non-numeric values are skipped, and stops when there is no maximum value (i.e. because there are no numeric values passed).

calculate_max <- function(values){
    max_value <- NA

    for (value in values){
        number <- as.numeric(value)

        if (is.na(number)){
            warning("Ignoring '", value,
                    "' as it is not a number")
        } else {
            if (is.na(max_value) || number > max_value){
                max_value = number
            }
        }
    }

    if (is.na(max_value)){
        stop("You can only find the maximum of numeric values")
    }

    return(max_value)
}

We can now test it with

calculate_max(c("cat", "dog", 5))
Warning in calculate_max(c("cat", "dog", 5)): NAs introduced by coercion
Warning in calculate_max(c("cat", "dog", 5)): Ignoring 'cat' as it is not a
number
Warning in calculate_max(c("cat", "dog", 5)): NAs introduced by coercion
Warning in calculate_max(c("cat", "dog", 5)): Ignoring 'dog' as it is not a
number
[1] 5