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
Timestrue <- 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