R for R Users

Part 2: Solving code problems

Malcolm Barrett

Strategies for solving code problems

  1. Restart your R session
  2. Debugging tools
  3. Reproducible examples
  4. LLMs

Debugging

Key concepts

  • Traceback: Shows the call stack leading to an error (where).
  • Interactive debugger: Allows you to step through code line by line (why).

Tracebacks

inner <- function(x) {
  x + 1
}

outer <- function(x) {
  inner(x)
}

outer("a")
Error in `x + 1`:
! non-numeric argument to binary operator

Tracebacks

traceback()
2: inner(x) at #6
1: outer("a") at #9

Tracebacks

options(error = rlang::entrace)
outer("a")
Error in `x + 1`:
! non-numeric argument to binary operator
rlang::last_trace()
<error/rlang_error>
Error in `x + 1`:
! non-numeric argument to binary operator
---
Backtrace:
    ▆
 1. └─global outer("a")
 2.   └─global inner(x)

browser()

inner <- function(x) {
  browser()
  x + 1
}

outer <- function(x) {
  inner(x)
}

outer("a")

Interactive debugging

Interactive debugger tips

Investigate objects

ls(), ls.str(),
str(), print()

Control execution

command operation
n next statement
c continue (leave interactive debugging)
s step into function call
f finish loop / function
where show previous calls
Q quit debugger

source: What They Forgot to Teach You about R

Breakpoints

Debugging console

RStudio error handling

IDE message only


IDE error inspector


IDE break in code


debug()

debug(sample)
sample(10, 1)
sample(10, 1)
undebug(sample)

debugonce()

library(ggplot2)
debugonce(ggplot2:::check_element)

ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  theme_void()

options(error = recover)

  • Always enter the debugger on error

Warnings

# default, stores warnings until top-level function returns
options(warn = 0)
# warnings are printed as they occur
options(warn = 1)
# upgrades warnings to errors
options(warn = 2)

# initiate recover on warning
# and save original settings
old <- options(warn = 2, error = recover)
# restore original settings
options(old)
# source: rstats.wtf

Making (minimal) reproducible examples

Minimal reproducible examples

library(ggplot2)
diabetes <- read.csv(
  "https://raw.githubusercontent.com/malcolmbarrett/au-stats412-612-01-reading_data/master/diabetes.csv"
)
just_height <- diabetes[, "height"]
ggplot(just_height, aes(x = height)) +
  geom_histogram() +
  coord_equal() +
  theme_minimal()
Error in `fortify()`:
! `data` must be a <data.frame>, or an object coercible by `fortify()`,
  or a valid <data.frame>-like object coercible by `as.data.frame()`.
Caused by error in `check_data_frame_like()`:
! `dim(data)` must return an <integer> of length 2.

Minimal reproducible examples

  • Make it reproducible (e.g. you may need library())
  • Make it minimal (e.g. remove unnecessary code)

Minimal reproducible examples

library(ggplot2)
just_bill_len <- penguins[, "bill_len"]
ggplot(just_bill_len, aes(x = bill_len)) +
  geom_histogram()
Error in `fortify()`:
! `data` must be a <data.frame>, or an object coercible by `fortify()`,
  or a valid <data.frame>-like object coercible by `as.data.frame()`.
Caused by error in `check_data_frame_like()`:
! `dim(data)` must return an <integer> of length 2.

reprex

  • Copy code to the clipboard and run reprex::reprex() in the console
  • Or use the RStudio addin

reprex

Source code and binaries

Package states

  • Package developers write in source code, then bundle the code to send to CRAN.
  • CRAN builds binaries or otherwise supplies the bundle to install.
  • We install the result with install.packages() and friends.
  • We bring an installed package into memory with library().

Package states

Package repositories

getOption("repos")
                       CRAN 
"https://cran.rstudio.com/" 
attr(,"IDE")
[1] TRUE
  • CRAN offers binaries for Windows and Mac, typically for the latest version and the version before that
  • CRAN archives package bundles for all versions that have been on CRAN, but these then need to be built from source

Package repositories

install.packages(
  "data.table",
  repos = c(CRAN = "https://packagemanager.posit.co/cran/2026-02-13")
)

Managing R installations

rig: The R Installation Manager

  • rig is a command line tool that you use in the terminal (not the R console) to manage R installations
  • rig add <version>, e.g. rig add 4.1.0 rig add release
  • rig default <version>, rig rstudio <version>

R Startup

R Startup

source: What They Forgot to Teach You about R

.Rprofile

  • R code that runs at startup
  • Can be used to set options, load development packages, and customize your R console
  • Should generally not be used for things that will affect reproducibility, e.g., loading a package required for code to work

.Rprofile

  • usethis::edit_r_profile() opens the user-level .Rprofile
  • interactive() is a useful function to conditionally run code only in interactive sessions, e.g. loading dev packages like devtools and usethis

.Rprofile

options(
  warnPartialMatchArgs = TRUE,
  warnPartialMatchAttr = TRUE,
  warnPartialMatchDollar = TRUE,
  repos = "https://packagemanager.posit.co/cran/latest"
)

.Rprofile

if (interactive()) {
  suppressMessages({
    library(devtools)
    library(usethis)
    library(reprex)
  })
}

.Rprofile

get_project_deps <- function(path = getwd()) {
  stopifnot(requireNamespace("renv", quietly = TRUE))
  renv::dependencies(path = path)$Package |>
    unique()
}

.Rprofile

# bad
library(ggplot2)
theme_set(theme_minimal())

.Renviron

  • Environment variables that are set at startup
  • Can be used to set API keys, database credentials, and other sensitive information

.Renviron

  • usethis::edit_r_environ() opens the user-level .Renviron
  • Use Sys.getenv() to access environment variables in your R code

.Renviron

GITHUB_PAT=ghp_1234567890abcdef1234567890abcdef12345678
SOME_API_KEY=abcdef1234567890abcdef1234567890

From R:

api_key <- Sys.getenv("SOME_API_KEY")
some_function_that_uses_api_key(api_key)

Scope of .Rprofile and .Renviron

  • User-level: ~/.Rprofile and ~/.Renviron
  • Project-level: ./.Rprofile and ./.Renviron
  • usethis::edit_r_profile(scope = "project") and usethis::edit_r_environ(scope = "project")
  • Tools such as {renv} also use .Rprofile for project-specific settings for package management

Your Turn

Positron Demo

Resources