safe_log <- .trap_safely(log)
safe_log("a")$result
NULL
$error
<simpleError in .f(...): non-numeric argument to mathematical function>
The purpose of minitrap is to provide zero-dependency versions of two purrr adverbs that are used to “trap” one or more aspects of the output of another function. Like all adverb functions they take one function as input, and return a modified function as the output. The README provides the full API reference and scope notes; this page provides a short tutorial that shows how to use the functions, and how they compose together.
The minitrap.R script supplies two functions:
.trap_safely(.f) is used to wrap .f so that a call which would normally produce an error instead returns a list containing two elements named result and error, with exactly one of the two set to NULL depending on whether the unmodified function would have errored when called the same way..trap_quietly(.f) is used to wrap .f so that all printed output, warnings, and messages are silently captured instead of shown, returning a four-element named list with components result, output, warnings, and messages.It contains no internal helpers.
.trap_safely()Ordinarily, a function that errors stops execution and requires you to wrap the call in tryCatch() if you want to capture the error and take some other action instead of stopping the execution. The goal of .trap_safely() is to invert this: it takes a function and returns a new one that never throws an error, instead capturing the error as data. Calling .trap_safely(log) on a non-numeric input, for example, doesn’t let the resulting error reach the console: instead, it returns a list with result = NULL and error set to the error condition object that would have been signalled:
$result
NULL
$error
<simpleError in .f(...): non-numeric argument to mathematical function>
A successful call returns a list with the same two elements, with error set to NULL instead, and result set to the calculated logarithm.
This is particularly useful when mapping a function over many inputs and some of them are expected to fail – rather than the whole iteration aborting on the first error, each element’s outcome (success or failure) is captured individually. Combining .trap_safely() with minimap’s .iter_map() is a convenient way to illustrate exactly that pattern.
[1] TRUE FALSE TRUE
As one would expect, this output shows that sqrt(4) succeeds, sqrt("a") errors, and sqrt(9) succeeds. The error that would normally be produced at the second step does not stop execution, and instead is captured and recorded. (Note that minitrap does not itself depend on minimap: this page sources that script to show the two minis operating together.)
.trap_quietly()Where .trap_safely() is about errors, .trap_quietly() is about outputs: printed output, return values, warnings, and messages. Rather than letting any of that reach the console, .trap_quietly() collects it all and hands it back as part of the return value:
$result
[1] 42
$output
[1] ""
$warnings
[1] "using a default"
$messages
[1] "starting\n"
Note the shape of the result: result holds the ordinary return value (i.e. 42), warnings and messages are character vectors with one entry per condition raised (in the order they occurred), and output is whatever was printed via cat()/print(), collapsed into a single string – empty here, since the original function would not have printed anything directly.
Crucially, .trap_quietly() does not catch errors – a function that errors still aborts the call, same as if it were called directly.
As you can see, the two functions serve complementary purposes: .trap_safely() catches errors but not outputs, whereas .trap_quietly() catches outputs but not errors. Should you need output-trapping and error-trapping together, you can compose the two functions:
$result
NULL
$error
<simpleError in .f(...): boom>
Pay attention to the order of composition: silence the function first, then make it safe. In the example above .trap_quietly() wraps the original function first, and .trap_safely() wraps the result, so that the error thrown inside the quietly-wrapped call becomes the thing that .trap_safely() catches. Composing in the opposite order does not produce the behaviour you most likely want.