rlang::global_entrance()
rlang::trace_back()
rlang::try_fetch()Writing and understanding R packages can be quite challenging.
To make things easier, I’ve compiled a short list of R libraries that may be helpful for this task.1
1 This is not a comprehensive list, but there doesn’t seem to be a CRAN task view for this sort of thing and I am trying to fill this gap. The closest match might be the “Reproducible Research” CRAN Task View.
2 It’s also worth noting that the packages I cite generally lean towards those actively supported by Posit, specifically under the collection of R packages maintained under “r-lib”. This isn’t necessarily good or bad, but it’s helpful to use software that is actively maintained. The hope is that one will be able to learn the package once, then use it for a long time and in a very productive manner. Also, a highly used package is a highly tested package, which helps make for a good user experience.
I’ve only used a subset of them, but I hope to update this blog post when I figure out whether I can make them live up to my hype.2
General Packages and Resources
-
rlang-
This package has many advanced features. In particular, it can help diagnose errors by formatting them into a readable format.
-
-
generics- Promises to make the UX of your package more similar to other packages, while reducing the number of dependencies.
- The chief example is letting you write a
tidymethod, without importingbroom.
- Comparing
RObjects-
waldo-
Colorful and user-friendly comparison of R-objects.
wald::compare() Contrast with
all.equal()andidentical()
-
-
digest-
This package is unusual in that it compares objects using hashes.
digest::digest() I imagine this could be particularly useful in cases of exact numerical comparisons with no tolerance, which may sometimes occur during statistical computing.
-
-
-
lobstr-
Better than
str().
-
-
ellipsis-
The
...functionality in R is powerful in a potentially dangerous way. This package helps users understand the use of....ellipsis::check_dots_empty() ellipsis::check_dots_unnamed() ellipsis::check_dots_used()
-
-
callr-
This package helps run
Rcode in a separate process. This might be handy when you’re inside a debugging environment and want to test something.callr::r()
-
-
evaluate-
Recreates command line behavior.
Perhaps this would be helpful to recreate a point in a debugging environment?
-
-
devtools- Default package for developing
Rpackages.
- Default package for developing
-
reprex- Must-have for reporting bugs and communicating with other developers.
-
sessioninfo- A must-have for communicating with other developers and comparing environments between machines.
-
clipr-
Intermediary between
Rand your clipboard.clipr::write_clip() clipr::read_clip() Could be helpful when you’re inside a debugging environment.
-
-
datapasta- Can be used to copy data and try to read into
Rmore easily.
- Can be used to copy data and try to read into
-
Air- Format
Rcode really fast, is not a package.
- Format
-
Writing R extensions
- Classic.
-
Advanced R
- Classic.
-
R Packages
- Classic.
Benchmarking
Benchmarking is important for comparing different implementations of the same idea. It can also help with performance tuning.
-
-
Comparing performance of different functions.
bench::mark()
-
-
-
Timing specific components of functions.
profvis::profvis()
-
-
-
Also for timing specific components of functions, but apparently more sophisticated and advanced.
proftools::profileExpr() proftools::plotProfileCallGraph() proftools::flameGraph() See this vignette for how to use it.
-
Static Code Analysis
These tools analyze R code without running them. It would probably be better to use these tools rather than trying to manually map out what happens to an R object using pen-and-paper.
-
-
Linting your code.
lintr::lint()
-
-
-
See what variables and functions a
Rsource code file uses.checkglobals::checkglobals()
-
-
-
Similar to
checkglobalsandglobals.codetools::findGlobals() codetools::findLocals()
-
-
-
Similar to
checkglobalsandcodetools.globals::Globals()
-
-
-
Dependency graph of a package and/or its functions.
pkgnet::CreatePackageReport() pkgnet::CreatePackageVignette() pkgnet::DefaultReporters() pkgnet::DependencyReporter() pkgnet::FunctionReporter() pkgnet::InheritanceReporter() pkgnet::PackageReport() pkgnet::SummaryReporter()
-
-
As per the vignette, “the CodeDepends package provides a flexible framework for statically analyzing R code (i.e., without evaluating it). It also contains higher-level functionality for: detecting dependencies between R code blocks or expressions, “tree-shaking” (pruning a script down to only the expressions necessary to evaluate a given expression), plotting variable usage timelines, and more.”
-
CodeDepends::getInputs() CodeDepends::inputCollector() CodeDepends::makeCallGraph() CodeDepends::makeTaskGraph() CodeDepends::makeVariableGraph() CodeDepends::getDetailedTimelines()
-
As per the associated master thesis’ abstract, “In this master thesis we describe the construction of a backward program slicer for the R programming language. Given a variable at a specific point in the program, a so-called”slicing criterion”, the slicer returns the subset of the program that might affect the value of the variable.”
Interfaces with the external program
flowr.This seems rather sophisticated and actively developed, rather than describe it very inaccurately, it would be better for me to link to its Wiki and the associated master thesis.
Tests
Tests are important for making sure that your code really does what it’s supposed to do. There’s also the popular philosophy of ‘test driven development’, which can help guide the development of your package based on some clear criteria, meaning tests.
-
-
Test coverage for your functions.
covr::report() covr::package_coverage()
-
-
- Default testing package.
-
-
This might be more lightweight than
testthatand require less set-up.unittest::ok() unittest::ok_group() unittest::ut_cmp_equal() unittest::ut_cmp_error() unittest::ut_cmp_identical() unittest::ut_cmp_warning()
-
-
This is like an interactive
testthatthat can write to your filesystem. See this recording.-
As per the package vignette, the package “
unitizerrequires you to review test outputs and confirm they are as expected. [In contrast, the package]testthatrequires you to assert what the test outputs should be beforehand.”unitizer::unitize() demo(package = "unitizer") browseVignettes("unitizer")
-
A testing package inspired by
JUnit.A notable feature seems to be the ability to track the value of a variable.
-
It apparently changes the random number generation. See this vignette for more information.
-
- Seems similar in purpose to
unittestand similar in usage totestthat.
- Seems similar in purpose to
Debugging
Debugging is helpful when something has gone wrong/unexpected.
General Resources on debugging in R:
C/C++ and Memory Leaks
When using C/C++, in particular, these utilities may be useful:
lldbvalgrindgdb-
memtools:-
Something about memory leaks and analyzing memory in
R.memtools::mem_snapshot() memtools::mem_igraph() memtools::root_ns_registry() memtools::mem_stash() memtools::obj_address() memtools::mem_paths_shortest()
-
Logging
Generally, logging in R can be used to store the output of a script. For our purposes, it can be helpful for selectively understanding the state and development of an R object(s) over time–then storing this output in a human-readable format.
This can be better than manually tracking an R object(s) and making mental notes of what happens to it.
-
-
Inspired by
Log4j.log4r::logger() log4r::log_info() log4r::log_warn() log4r::log_debug() Website seems to be currently down: See https://github.com/r-lib/log4r and https://log4r.r-lib.org/dev/, instead.
-
-
-
Inspired by the
futile.loggerR package and Python’slogging.logger::log_info() logger::log_warn() logger::log_debug() logger::log_formatter() This seems to overlap substantially with
log4r.
-
-
-
Allows tracking of an
Robject and an examination of how it changes.
-
-
-
A quick glance seems to make this out to be a logger that doesn’t require as much manual fiddling of what to log.
logrx::axecute() This also seems to be part of the
pharmaverseseries of packages.
-
-
- Logging that is specific to
dplyrandtidyr.
- Logging that is specific to
-
-
An easy logger. Presumably similar to
logrx, in purpose, but is supposed to be familiar to SAS users. See the available options here.
-
-
-
As I copy pasted from the
whirlOverview:“The whirl package provide functionalities for executing scripts in batch and simultaneously getting a log from the individual executions. A log from script execution is in many pharmaceutical companies a GxP requirement, and the whirl package honors this requirement by generating a log that, among other things, contains information about:
- Status (did the script run with any error or warnings)
- The actual code itself
- Date and time of execution
- The environment the script was executed under (session info)
- Information about packages versions that was utilized
- Environmental variables
And all this is wrapped into a nicely formatted html document that is easy to navigate.”
whirl::run()
-
Printing to Command Line
-
- Formats
Rterminal output in pretty ways.
- Formats
-
- Good looking terminal output.
-
- Good looking printing of units.
-
- Good looking printing of columns.
Blog Post Computational Environment
We used R v. 4.5.1 (R Core Team 2025) and the following R packages: bench v. 1.1.4 (Hester and Vaughan 2025), callr v. 3.7.6 (Csárdi and Chang 2024), checkglobals v. 0.1.3 (Chau 2025), clipr v. 0.8.0 (Lincoln 2022), CodeDepends v. 0.6.6 (Lang et al. 2024), codetools v. 0.2.20 (Tierney 2024), covr v. 3.6.4 (Hester 2023), crayon v. 1.5.3 (Csárdi 2024a), datapasta v. 3.1.0 (McBain et al. 2020), debugme v. 1.2.0 (Csárdi 2024b), devtools v. 2.4.5 (Wickham et al. 2022), digest v. 0.6.37 (Eddelbuettel 2024), ellipsis v. 0.3.2 (Wickham 2021), evaluate v. 1.0.5 (Wickham and Xie 2025), flowr v. 0.0.3 (Sihler 2025), generics v. 0.1.4 (Wickham, Kuhn, and Vaughan 2025), globals v. 0.18.0 (Bengtsson 2025), lintr v. 3.2.0 (Hester et al. 2025), lobstr v. 1.1.2 (Wickham 2022), log4r v. 0.4.4 (White and Jacobs 2024), logger v. 0.4.1 (Daróczi and Wickham 2025), logr v. 1.3.9 (Bosak 2025), logrx v. 0.4.0 (Kosiba et al. 2025), lumberjack v. 1.3.1 (M. P. J. van der Loo 2021), memtools v. 0.1.0.9000 (Henry 2025), pkgnet v. 0.5.0 (Burns, Lamb, and Qi 2024), prettyunits v. 1.2.0 (Csardi 2023), proftools v. 0.99.3 (Tierney and Jarjour 2020), profvis v. 0.4.0 (Wickham et al. 2024), rmarkdown v. 2.29 (Xie, Allaire, and Grolemund 2018; Xie, Dervieux, and Riederer 2020; Allaire et al. 2024), RUnit v. 0.4.33.1 (Burger, Juenemann, and Koenig 2025), sessioninfo v. 1.2.3 (Wickham et al. 2025), testthat v. 3.2.3 (Wickham 2011), tidylog v. 1.1.0 (Elbers 2024), tidyverse v. 2.0.0 (Wickham et al. 2019), tinytest v. 1.4.1 (M. van der Loo 2020), unitizer v. 1.4.22 (Gaslam 2025), unittest v. 1.7.0 (Lentin and Hennessey 2024), waldo v. 0.6.2 (Wickham 2025), whirl v. 0.3.1 (Thomsen et al. 2025).
─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.5.1 (2025-06-13)
os Ubuntu 22.04.5 LTS
system x86_64, linux-gnu
ui X11
language en_CA:en
collate en_CA.UTF-8
ctype en_CA.UTF-8
tz America/Toronto
date 2025-09-17
pandoc 3.6.3 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
quarto 1.6.33 @ /usr/local/bin/quarto
─ Packages ───────────────────────────────────────────────────────────────────
! package * version date (UTC) lib source
assertthat 0.2.1 2019-03-21 [1] RSPM
backports 1.5.0 2024-05-23 [1] RSPM
bench * 1.1.4 2025-01-16 [1] RSPM
BiocGenerics 0.54.0 2025-04-15 [1] Bioconduc~
BiocManager 1.30.26 2025-06-05 [1] RSPM
brio 1.1.5 2024-04-24 [1] RSPM
cachem 1.1.0 2024-05-16 [1] RSPM
callr * 3.7.6 2024-03-25 [1] RSPM
checkglobals * 0.1.3 2025-02-06 [1] RSPM
cli * 3.6.5 2025-04-23 [1] RSPM
clipr * 0.8.0 2022-02-22 [1] RSPM
clisymbols 1.2.0 2017-05-21 [1] RSPM
CodeDepends * 0.6.6 2024-04-07 [1] RSPM
P codetools * 0.2-20 2024-03-31 [?] CRAN (R 4.5.1)
common * 1.1.3 2024-04-05 [1] RSPM
covr * 3.6.4 2023-11-09 [1] RSPM
crayon * 1.5.3 2024-06-20 [1] RSPM
data.table 1.17.8 2025-07-10 [1] RSPM
datapasta * 3.1.0 2020-01-17 [1] RSPM
debugme * 1.2.0 2024-04-25 [1] RSPM
devtools * 2.4.5 2022-10-11 [1] RSPM
diffobj 0.3.6 2025-04-21 [1] RSPM
digest * 0.6.37 2024-08-19 [1] RSPM
dplyr 1.1.4 2023-11-17 [1] RSPM
DT 0.34.0 2025-09-02 [1] RSPM
ellipsis * 0.3.2 2021-04-29 [1] RSPM
evaluate * 1.0.5 2025-08-27 [1] RSPM
fastmap 1.2.0 2024-05-15 [1] RSPM
flowr * 0.0.3 2025-09-17 [1] Github (flowr-analysis/flowr-r-adapter@b171729)
formatR 1.14 2023-01-17 [1] RSPM
fs 1.6.6 2025-04-12 [1] RSPM
futile.logger 1.4.3 2016-07-10 [1] RSPM
futile.options 1.0.1 2018-04-20 [1] RSPM
generics * 0.1.4 2025-05-09 [1] RSPM
globals * 0.18.0 2025-05-08 [1] RSPM
glue 1.8.0 2024-09-30 [1] RSPM
graph 1.86.0 2025-04-15 [1] Bioconduc~
grateful * 0.3.0 2025-09-04 [1] RSPM
htmltools 0.5.8.1 2024-04-04 [1] RSPM
htmlwidgets 1.6.4 2023-12-06 [1] RSPM
httpuv 1.6.16 2025-04-16 [1] RSPM
igraph 2.1.4 2025-01-23 [1] RSPM
jsonlite 2.0.0 2025-03-27 [1] RSPM
knitr 1.50 2025-03-16 [1] RSPM
lambda.r 1.2.4 2019-09-18 [1] RSPM
later 1.4.4 2025-08-27 [1] RSPM
P lattice 0.22-7 2025-04-02 [?] CRAN (R 4.5.1)
lazyeval 0.2.2 2019-03-15 [1] RSPM
lifecycle 1.0.4 2023-11-07 [1] RSPM
lintr * 3.2.0 2025-02-12 [1] RSPM
lobstr * 1.1.2 2022-06-22 [1] RSPM
log4r * 0.4.4 2024-10-12 [1] RSPM
logger * 0.4.1 2025-09-11 [1] RSPM
logr * 1.3.9 2025-03-26 [1] RSPM
logrx * 0.4.0 2025-05-05 [1] RSPM
lumberjack * 1.3.1 2023-03-29 [1] RSPM
magrittr 2.0.4 2025-09-12 [1] RSPM
Matrix 1.7-4 2025-08-28 [1] RSPM
memoise 2.0.1 2021-11-26 [1] RSPM
memtools * 0.1.0.9000 2025-09-17 [1] Github (r-lib/memtools@803d1f1)
mime 0.13 2025-03-17 [1] RSPM
miniUI 0.1.2 2025-04-17 [1] RSPM
pillar * 1.11.1 2025-09-17 [1] CRAN (R 4.5.1)
pkgbuild 1.4.8 2025-05-26 [1] RSPM
pkgconfig 2.0.3 2019-09-22 [1] RSPM
pkgload 1.4.0 2024-06-28 [1] RSPM
pkgnet * 0.5.0 2024-05-03 [1] RSPM
png 0.1-8 2022-11-29 [1] RSPM
prettyunits * 1.2.0 2023-09-24 [1] RSPM
processx 3.8.6 2025-02-21 [1] RSPM
proftools * 0.99-3 2020-07-08 [1] RSPM
profvis * 0.4.0 2024-09-20 [1] RSPM
promises 1.3.3 2025-05-29 [1] RSPM
ps 1.9.1 2025-04-12 [1] RSPM
purrr 1.1.0 2025-07-10 [1] RSPM
R6 2.6.1 2025-02-15 [1] RSPM
Rcpp 1.1.0 2025-07-02 [1] RSPM
remotes 2.5.0 2024-03-17 [1] RSPM
P renv 1.1.5 2025-07-24 [?] RSPM
reprex * 2.1.1 2024-07-06 [1] RSPM
reticulate 1.43.0 2025-07-21 [1] RSPM
rex 1.2.1 2021-11-26 [1] RSPM
rlang * 1.1.6.9000 2025-09-17 [1] Github (r-lib/rlang@7371bac)
rmarkdown 2.29 2024-11-04 [1] RSPM
rstudioapi 0.17.1 2024-10-22 [1] RSPM
RUnit * 0.4.33.1 2025-06-17 [1] RSPM
sessioninfo * 1.2.3 2025-02-05 [1] RSPM
shiny 1.11.1 2025-07-03 [1] RSPM
stringi 1.8.7 2025-03-27 [1] RSPM
stringr 1.5.2 2025-09-08 [1] RSPM
testthat * 3.2.3 2025-01-13 [1] RSPM
tibble 3.3.0 2025-06-08 [1] RSPM
tidylog * 1.1.0 2024-05-08 [1] RSPM
tidyr 1.3.1 2024-01-24 [1] RSPM
tidyselect 1.2.1 2024-03-11 [1] RSPM
tinytest * 1.4.1 2023-02-22 [1] RSPM
unitizer * 1.4.22 2025-03-19 [1] RSPM
unittest * 1.7-0 2024-08-16 [1] RSPM
urlchecker 1.0.1 2021-11-30 [1] RSPM
usethis * 3.2.1 2025-09-06 [1] RSPM
vctrs 0.6.5 2023-12-01 [1] RSPM
visNetwork 2.1.4 2025-09-04 [1] RSPM
waldo * 0.6.2 2025-07-11 [1] RSPM
whirl * 0.3.1 2025-08-25 [1] RSPM
withr 3.0.2 2024-10-28 [1] RSPM
xfun 0.53 2025-08-19 [1] RSPM
XML 3.99-0.19 2025-08-22 [1] RSPM
xml2 1.4.0 2025-08-20 [1] RSPM
xtable 1.8-4 2019-04-21 [1] RSPM
yaml 2.3.10 2024-07-26 [1] RSPM
[1] /home/mstruong/Documents/RStudio/website/emstruong.github.io/renv/library/linux-ubuntu-jammy/R-4.5/x86_64-pc-linux-gnu
[2] /home/mstruong/.cache/R/renv/sandbox/linux-ubuntu-jammy/R-4.5/x86_64-pc-linux-gnu/179fe56a
* ── Packages attached to the search path.
P ── Loaded and on-disk path mismatch.
──────────────────────────────────────────────────────────────────────────────
References
Reuse
Citation
@online{truong2025,
author = {Truong, Michael S.},
title = {Resources and {Tools} for {Writing} {Your} {Own} and
{Understanding} {Other} {People’s} {R} {Packages} (2025)},
date = {2025-09-17},
langid = {en}
}