--- title: "Using {typed} in packages" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Using {typed} in packages} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( error = TRUE, collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(typed, warn.conflicts = FALSE) ``` Here are some recommendations to use {typed} in your own package and define custom types.. ## Use {typed} in your package Call this to set up your package so you can use 'typed', by editing the DESCRIPTION file and editing or creating 'R/your.pkg-package.R' ```{r, eval = FALSE} typed::use_typed() devtools::document() # to actually import from the generated roxygen2 comments ``` ## Use existing types to define your functions Here's an example where we define types for the return value, for all arguments, and for a `msg` variable in the body. The use of roxygen2 tags is standard, except that you'll need to make sure to add the `@name` tag. ```{r} #' add_or_subtract #' #' @param x double of length 1 #' @param y double of length 1 #' @param subtract whether to subtract instead of adding #' @export #' @name add_or_subtract add_or_subtract <- Double(1) ? function ( x = ? Double(1), y = ? Double(1), subtract = FALSE ? Logical(1, anyNA = FALSE) ) { Character(1) ? msg if(subtract) { msg <- "subtracting" message(msg) return(x - y) } msg <- "adding" message(msg) x + y } ``` The created function will be the following: ```{r} add_or_subtract ``` We see that `?` is not present in the generated code, instead we have `check_arg()`, `declare()`, `check_output()`. The substitution is done by the first `?`, it is both for efficiency and readability, unfamiliar users might be intimidated by `?` and calls to `?` don't print nicely in base R. Note that you're free to use these functions directly in your code if you don't like the `?` Syntax. ## Define your own types from existing types A way to define custom types is to wrap existing ones and add constraints ```{r} Fruit <- function() { Character( length = 1, ... = "`value` is not a fruit!" ~ . %in% c("apple", "pear", "cherry") # we could have several args named ... to apply multiple checks ) } Fruit() ? x <- "potatoe" ``` The type `Any()` is the most general, but in many case it's a good idea to start from a more restricted type so you get its own checks for free. ```{r} Fruit() ? x <- 1L ``` Here's a case where starting from `Any()` makes sense : ```{r} Ggplot <- function() { Any(... = "Expected a ggplot object" ~ ggplot2::is.ggplot(value)) } Ggplot() ? x <- 1 ``` A custom type might also just be a restriction on an existing type using existing arguments. In the following example we apply a simple restriction to an existing type, using the existing argument `length`. Here we restrict the length but keep other args flexible by forwarding them: ```{r, error = TRUE} ScalarInteger1 <- function(null_ok = FALSE, ...) { Integer(length = 1, null_ok = null_ok, ...) } ScalarInteger1() ? x <- c(1L, 2L) ``` Here we remove all flexibility: ```{r, error = TRUE} ScalarInteger2 <- function() { Integer(length = 1) } ScalarInteger2() ? x <- c(1L, 2L) ``` ## Define your own types from scratch We can define a check function and use `as_assertion_factory()` on it. ```{r, error = TRUE} check_is_ggplot <- function(x) { if(!ggplot2::is.ggplot(x)) { msg <- "Class mismatch" info1 <- "Expected a ggplot object" info2 <- sprintf("Got an object of class <%s>", paste(class(x), collapse = "/")) rlang::abort( c(msg, i = info1, x = info2) ) } } Ggplot <- as_assertion_factory(check_is_ggplot) Ggplot() ? x <- 1 ``` Another example, to impose a data type based on a prototype: ```{r} check_cars <- function(x) vctrs::vec_assert(x, cars) Cars <- as_assertion_factory(check_cars) Cars() ? x <- iris ``` Or if we want to be more general: ```{r} check_valid_ptype <- function(x, ptype) vctrs::vec_assert(x, ptype) Ptype <- as_assertion_factory(check_valid_ptype) Ptype(cars) ? x <- iris ``` `as_assertion_factory()` [is actually used to build the native assertion factories of this package](https://github.com/moodymudskipper/typed/blob/master/R/06_native_types.R)