# Get Started with chk

## Introduction

`chk` is an R package for developers to check user-supplied function arguments. It is designed to be simple, customizable and fast.

### `chk_` Functions

`chk_` functions check the properties of individual objects. For example `chk_flag(x)` checks whether `x` is a flag, i.e., a non-missing logical vector of length 1.

`chk_` functions are called for their side-effects, i.e., they throw an informative error if the object fails the check. Although do return an invisible copy of the first argument so they can be used in pipes.

    library(chk)
    y <- TRUE
    chk_flag(y)
    y <- NA
    chk_flag(y)
    #> Error:
    #> ! `y` must be a flag (TRUE or FALSE).

The error messages, which follow the tidyverse style guide, are designed to allow the user to quickly identify the problem with the argument value(s) they are providing. The errors are rlang errors of subclass `'chk_error'`.

### `vld_` Functions

Each `chk_` function has a matching `vld_` function which returns a flag indicating whether the object passed the check.

    vld_flag(TRUE)
    #> [1] TRUE
    vld_flag(NA)
    #> [1] FALSE

The `vld_` functions allow developers to provide their own error messages.

    if (!vld_flag(NA)) abort_chk("`NA` is not TRUE or FALSE!!")
    #> Error:
    #> ! `NA` is not TRUE or FALSE!!

## Using chk

The `chk_` functions are designed to be used within functions. Consequently, when constructing an error message they use the name of the object that they received as this is expected to be the name of the argument.

    fun1 <- function(x) {
      chk_whole_number(x)
      # use x
    }

    fun1(1)
    y <- 1.3
    fun1(x = y)
    #> Error in `fun1()`:
    #> ! `x` must be a whole number (non-missing integer scalar or double equivalent).

If this is not the case, developers can provide a different name using the `x_name` argument.

    x <- NA
    chk_flag(x, x_name = "`zzz`")
    #> Error:
    #> ! `zzz` must be a flag (TRUE or FALSE).

IMPORTANT NOTE

As the `chk_` (and `vld_`) functions are not expected to be directly exposed to users they don’t check any of their arguments (other than the object of interest of course!) to ensure that they are as fast as possible.

## Extending chk

The `chk_flag()` function illustrates the general structure of a `chk_` function.

    chk_flag
    #> function(x, x_name = NULL){
    #>   if(vld_flag(x)) return(invisible(x))
    #>   if(is.null(x_name))  x_name <- deparse_backtick_chk(substitute(x))
    #>   abort_chk(x_name, " must be a flag (TRUE or FALSE)")
    #> }
    #> <bytecode: 0x7fe802835670>
    #> <environment: namespace:chk>

A `chk_` function initially checks the object (using its `vld_` partner) and if the object passes the check immediately returns an invisible copy of the object. If, and only if, the object fails the check does the `chk_` function construct and then throw an informative error message.

The `deparse_backtick_chk()` and `abort_chk()` functions are exported to make it easy for programmers to develop their own `chk_` functions. The chk-lgl.R script illustrates the general template to use when developing your own `chk_` functions.

### `abort_chk()`

The `abort_chk()` function converts multiple arguments to a string using `paste0(..., collapse = '')` and provides number sensitive `sprintf`-like types. By default it also capitalizes the first character and adds a missing period.

    abort_chk("There %r %n problem director%y%s.", n = 1)
    #> Error:
    #> ! There is 1 problem directory.
    abort_chk("there %r %n ", "problem director%y%s", n = 2)
    #> Error:
    #> ! There are 2 problem directories.

### `check_` Functions

The `check_` functions are more complex then the `chk_` functions which make them slower but makes doing some general tests easier.