Validators and Helpers
Part of the Object Oriented Programming section of Coddy's R journey. Lesson 5 of 57.
The constructor checks types; a validator checks values. By convention validate_money() takes an object, calls stop() with a clear message for each rule it breaks, and returns the object when everything is fine. call. = FALSE keeps the function call out of the message:
new_money <- function(amount = double(), currency = character()) {
stopifnot(is.double(amount), is.character(currency))
structure(list(amount = amount, currency = currency), class = "money")
}
validate_money <- function(x) {
if (x$amount < 0) stop("amount must not be negative", call. = FALSE)
if (nchar(x$currency) != 3) stop("currency must have 3 letters", call. = FALSE)
x
}
m <- validate_money(new_money(-5, "EUR"))Output:
Error: amount must not be negative
Execution haltedThe helper is the function other code calls. It is named after the class, converts its input to the right types, fills in defaults, and passes the result through the constructor and the validator:
new_money <- function(amount = double(), currency = character()) {
stopifnot(is.double(amount), is.character(currency))
structure(list(amount = amount, currency = currency), class = "money")
}
validate_money <- function(x) {
if (x$amount < 0) stop("amount must not be negative", call. = FALSE)
x
}
money <- function(amount, currency = "EUR") {
validate_money(new_money(as.double(amount), toupper(currency)))
}
m <- money("12", "usd")
cat(m$amount, m$currency)Output:
12 USDCode that reads user input catches the validator's errors with tryCatch() and shows conditionMessage(e), the text passed to stop():
validate_age <- function(x) {
if (x$years < 0) stop("age must not be negative", call. = FALSE)
if (x$years > 150) stop("age is too large", call. = FALSE)
x
}
age <- function(years) validate_age(structure(list(years = as.double(years)), class = "age"))
for (input in c("30", "-2", "200")) {
result <- tryCatch(paste("ok", age(input)$years), error = function(e) conditionMessage(e))
cat(result, "\n")
}Output:
ok 30
age must not be negative
age is too large Each of the three functions has one job. new_money() is strict and fast, for code that already has the right types. validate_money() holds the rules about values, which can be slow or many. money() is friendly and is what the rest of the program uses:
new_money() # types only; builds the object with structure()
validate_money() # value rules; stop() with a message, else return x
money() # converts input, then validate_money(new_money(...))Challenge
Easynew_score(points, max) in Score.R builds a score object. Complete the other functions in the same file:
validate_score(x)stops withpoints must not be negative,max must be positiveorpoints must not exceed max, checked in that order, and otherwise returnsx.score(points, max = 100)converts both arguments withas.double()and returnsvalidate_score(new_score(...)).format.score(x, ...)returns45/50 (90%), with the percentage rounded to a whole number.
Use call. = FALSE in every stop(). The supplied code reads lines 45 50, prints the formatted score, or error: and the message.
Your code goes in Score.R. main.R holds the supplied input/output code and cannot be edited.
Try it yourself
source("Score.R")
# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
s <- tryCatch(score(p[1], p[2]), error = function(e) conditionMessage(e))
if (is.character(s)) cat("error: ", s, "\n", sep = "") else cat(format(s), "\n", sep = "")
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1S3 Basics
Working With FilesLists With a ClassConstructor FunctionsPrint and Format MethodsValidators and HelpersRecap - Temperatures4Encapsulation in R
Closures as ObjectsEnvironments as ObjectsAccessor FunctionsGuarding StateRecap - Parking Meter2S3 Generics and Methods
Generics and UseMethodDefault MethodsMethods for Base GenericsNextMethod BasicsRecap - Shape Areas8Reference Classes
Defining Reference ClassesMethods and Field UpdatesCopy SemanticsInheritance and callSuperRecap - Task Queue11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Online R compiler