library(rdantic)
#>
#> Attaching package: 'rdantic'
#> The following object is masked from 'package:graphics':
#>
#> frame
#> The following object is masked from 'package:base':
#>
#> dateEvery validation failure in rdantic – from a bare type, a struct, or a typed function – has the same shape: a list of problems, each naming the path where it occurred, what was expected, what arrived, and (often) a hint about why. This vignette covers the three ways to get at that information, and when to reach for each.
Errors are machine-readable
By default, a failed validation throws a condition of class
typed_error whose $problems field is a list of
path / expected / got /
hint records – so tooling can consume it, not just
people.
User <- struct("User", id = int[1], name = chr[1])
tryCatch(User(id = "x", name = 1), typed_error = function(e)
data.frame(
path = vapply(e$problems, `[[`, "", "path"),
expected = vapply(e$problems, `[[`, "", "expected"),
got = vapply(e$problems, `[[`, "", "got")
))
#> path expected got
#> 1 $id int[1] chr[1] "x"
#> 2 $name chr[1] num[1] 1Because typed_error is a distinct condition class,
tryCatch() can single it out from other errors a call might
raise.
Validating without throwing
When wrong input is expected rather than exceptional – a web
form, a file upload, a config file – throwing on every bad value is the
wrong shape. try_parse() returns the same problem records
instead of raising them:
r <- try_parse(User, list(id = 1.5, name = "Ada"))
r$ok
#> [1] FALSE
str(r$problems[[1]])
#> List of 4
#> $ path : chr "$id"
#> $ expected: chr "int[1]"
#> $ got : chr "num[1] 1.5"
#> $ hint : chr "not a whole number"try_parse() returns a list with ok,
value (the validated/coerced value when ok is
TRUE) and problems (always a list, empty when
there is nothing to report).
A yes/no answer
When only “is this valid” matters, not why, is_valid()
skips building any problem detail and returns a plain
TRUE/FALSE:
Picking one
| Situation | Use |
|---|---|
| Wrong input is a bug in the caller | let it throw, or tryCatch(..., typed_error = ...)
|
| Wrong input is routine (forms, uploads, config) | try_parse(T, x) |
| Only need a yes/no answer | is_valid(T, x) |
| The type is in a variable, not a literal |
parse_as(T, x) (same as T(x)) |
Turning checks off
Validation has a real, if small, cost. fn() checks can
be disabled globally with options(rdantic.check = FALSE)
once a typed function’s contract is trusted – see
vignette("typed-functions"). There is no equivalent switch
for structs or bare types: their whole purpose is that an instance can
never become invalid, so disabling their checks is not offered.