Benchmarking chk

library(chk)
library(microbenchmark)

Conditional Checking


fun_checking <- function(x) {
  chk_flag(x)
  NULL
}

.fun_checking <- function(x) {
  NULL
}

fun_checking_arg <- function(x, chk = TRUE) {
  if(chk) {
    chk_flag(x)
  }
  NULL
}
times <- summary(microbenchmark(
  fun_checking(TRUE),
  .fun_checking(TRUE),
  fun_checking_arg(TRUE, chk = TRUE),
  fun_checking_arg(TRUE, chk = FALSE),
  unit = "us", times = 10000L
))[c("expr", "median")]
print(times)
#>                                  expr median
#> 1                  fun_checking(TRUE)  0.999
#> 2                 .fun_checking(TRUE)  0.183
#> 3  fun_checking_arg(TRUE, chk = TRUE)  1.083
#> 4 fun_checking_arg(TRUE, chk = FALSE)  0.271

In summary, avoiding chk_flag() saves about 0.81 \(\mu\)s while conditional checking using a chk argument costs about 0.084 \(\mu\)s.

It is recommended to always use unconditional checking unless profiling indicates the checks are a bottleneck.

If the bottleneck is due to repeated calls within the package the recommended option is to write an internal version of the function that has no checks. Alternatively if the bottleneck is due to repeated calls by a user or other package then the recommended option is to add a chk argument that the user can explicitly turn off.

chk Times

true <- TRUE
false <- FALSE
one <- 1
oneL <- 1L
string <- "1"
date <- as.Date(1, origin = as.Date("1970-01-01"))
datetime <- as.POSIXct(1, origin = as.Date("1970-01-01"))
null <- NULL
named <- c("1" = 1)
fun <- function() NULL
data <- data.frame(one = one)
summary(microbenchmark(
  chk_true(true),
  chk_false(false),
  chk_flag(true),
  chk_lgl(true),
  chk_number(oneL),
  chk_number(one),
  chk_whole_number(oneL),
  chk_whole_number(one),
  chk_string(string),
  chk_date(date),
  chk_datetime(datetime),
  chk_whole_numeric(oneL),
  chk_whole_numeric(one),
  chk_not_any_na(one),
  chk_unique(one),
  chk_unique(data),
  chk_unique(data, incomparables = NA),
  chk_null(null),
  chk_not_null(one),
  chk_named(named),
  chk_unused(),
  chk_used(one),
  chk_function(fun),
  chk_s3_class(one, "numeric"),
  chk_identical(one, one),
  chk_equal(one, one),
  chk_equivalent(one, one),
  chk_lt(one, 2),
  chk_lte(one, one),
  chk_gt(one, 0),
  chk_gte(one, one),
  chk_range(one),
  chk_subset(one, one),
  chk_superset(one, one),
  chk_match(string),
  chk_all(true, chk_true),
  chkor(),
  chkor(chk_number(one)),
  chkor(chk_number(one), chk_proportion(one)),
  unit = "us", times = 10000L
))[c("expr", "median")]
#>                                           expr   median
#> 1                               chk_true(true)   1.3830
#> 2                             chk_false(false)   1.4780
#> 3                               chk_flag(true)   1.3960
#> 4                                chk_lgl(true)   1.2190
#> 5                             chk_number(oneL)   1.4230
#> 6                              chk_number(one)   1.3870
#> 7                       chk_whole_number(oneL)   2.0690
#> 8                        chk_whole_number(one)  21.6430
#> 9                           chk_string(string)   1.0005
#> 10                              chk_date(date)   7.4700
#> 11                      chk_datetime(datetime)   9.3320
#> 12                     chk_whole_numeric(oneL)   1.0660
#> 13                      chk_whole_numeric(one)  20.9110
#> 14                         chk_not_any_na(one)   1.1860
#> 15                             chk_unique(one)   7.5260
#> 16                            chk_unique(data)  20.5250
#> 17        chk_unique(data, incomparables = NA) 251.9695
#> 18                              chk_null(null)   1.0550
#> 19                           chk_not_null(one)   1.0910
#> 20                            chk_named(named)   1.2700
#> 21                                chk_unused()   0.9200
#> 22                               chk_used(one)   1.3580
#> 23                           chk_function(fun)   1.5860
#> 24                chk_s3_class(one, "numeric")   2.2180
#> 25                     chk_identical(one, one)   1.2200
#> 26                         chk_equal(one, one)  21.9675
#> 27                    chk_equivalent(one, one)  17.1290
#> 28                              chk_lt(one, 2)   2.3770
#> 29                           chk_lte(one, one)   2.3810
#> 30                              chk_gt(one, 0)   2.3560
#> 31                           chk_gte(one, one)   2.4070
#> 32                              chk_range(one)   3.9960
#> 33                        chk_subset(one, one)   2.8080
#> 34                      chk_superset(one, one)   2.7630
#> 35                           chk_match(string)  10.1895
#> 36                     chk_all(true, chk_true)  30.9410
#> 37                                     chkor()  55.6980
#> 38                      chkor(chk_number(one)) 116.9085
#> 39 chkor(chk_number(one), chk_proportion(one)) 118.3540