TLDR:

  • Breakpoints work most reliable if they are set before launching the debugger
  • The debug mode “Debug R-Function” sometimes works better to set/unset breakpoints
  • To set breakpoints in packages, they need to be specified in the launch config entries “debuggedPackages” or “loadPackages”.

Setting breakpoints during debugging

The most reliable way to use breakpoints is to set them before launching the debugger and not modifying them afterwards.

Breakpoints can be (un)set in the UI while the debugger is running code, but they won’t take effect until the debugger is stopped on a breakpoint or done running its current evaluation.

(Un)setting breakpoints while the program is stopped on a breakpoint can be a bit hit or miss, since the body of the currently executed function cannot be modified (which is done to set breakpoints). Therefore, setting a breakpoint in the same function as the breakpoint where you’re currently stopped usually won’t work:

f <- function(){
    print(1) # <-- Set breakpoint here
    print(2)
    print(3) # <-- Setting breakpoint here while stopped on first breakpoint won't work
    print(4)
}
f()

If a function is called repeatedly, the new breakpoint should work on the next iteration though: (This example works with debug mode “Debug R-Function”)

f <- function(){
    print(1) # <-- Setting breakpoint here while stopped on the other breakpoint should work on the next iteration
    print(2)
    print(3) # <-- Set breakpoint here
    print(4)
}

main <- function(){
    for(i in 1:2){
        f()
    }
}

Setting breakpoints in a function that is not being executed should always work:

f <- function(){
    print(1) # <-- Set breakpoint here
    print(2)
    g()
    print(4)
}
g <- function(){
    print(3) # <-- Setting breakpoint here while stopped on the other breakpoint should work
}
f()

Debug modes

The debug modes “Debug R-File” and “Launch Workspace” use a custom version of source(), which makes changes to the R code in order to set breakpoints. To provide a somewhat ‘cleaner’ method of running code, the debug mode “Debug R-Function” can be used. In this mode, the specified file is executed using the default source() command and breakpoints are set by using R’s trace(..., tracer=browser) function, which is more robust than the custom breakpoint mechanism.

Breakpoints in packages

Packages can be debugged using load_all() from pkgload. To do so, it is required to install pkgload (part of devtools). By default, load_all will be masked by a modified version that automatically sets breakpoints in the loaded package and attaches the modified versions of print, cat, message. To always load a package when launching a debug session, you can specify an array of paths in the launch config entry "loadPackages".

If it is preferred to properly install a package before debugging, the package can be specified in the launch config entry "debuggedPackages". To keep the required source information during installation, the following points might help:

  • The package must be installed from source code (not CRAN or .tar.gz)
  • The flag --with-keep.source should be set
  • Extensions containing C code might cause problems. Sometimes it helps to install the package using devtools::install(quick=FALSE, ...) to compile the binaries and again with devtools::install(quick=TRUE, ...) to retain the source information.