R
debugging
Feb 15, 2018     3 minutes read

1. What is debugging and why would use use it?

2. Functions frequently used for debugging purposes

Rarely used directly, but important to understand how debug() works.

A short example:

Let’s say that function my_function returns an error. (In this case we cause an error intentionally.)

my_function <- function(x) {
  print(x)
  stop("This is an error.")
  print(x + 10)
}
my_function(x = 2)
## [1] 2
## Error in my_function(x = 2): This is an error.

In order to find out where exactly the error occured, i.e. which statement caused it, we may enter the function’s body and run the statements line by line.

my_function <- function(x) {
  browser()  # just add this line of code into your function's definition 
  print(x)
  stop("This is an error.")
  print(x + 10)
}
my_function(x = 2)

Right now you are in my_function()’s environment, which you can check by typing environment() or ls(). You can also see that the prompt has changed. Type n until you get to the line of code which produces an error.

Tip: To skip a loop, type c.

To quit browser() earlier, type q and hit Enter.

Or the most useful debugging functions.

Let’s assume that you invoke a function inside of a function:

my_inside_function <- function(x_inside) {
  print(paste("x_inside: ", x_inside + 10))
  print("after error")
}
my_function <- function(x) {
  print(x)
  my_inside_function("some text")
  print(x + 10)
}
my_function(x = 2)
## [1] 2
## Error in x_inside + 10: non-numeric argument to binary operator

which produces an error. You don’t know yet where exactly the error ocurred, so now you should write:

debug(my_function)
my_function(x = 2)

to start searching for the bug right from the top function. A new, weird-looking prompt appears: it is the same prompt as invoked by the browser() function, inside my_function. Type ls() and you will see that you actually are inside of my_function’s environment. Hit n a couple of times until you reach the error. You can see that it was my_inside_function that caused an error. Debugging my_inside_function will lead you straight to the statement which caused an error, but before entering my_inside_function, stop observing my_function:

undebug(my_function)

And then debug my_inside_function:

debug(my_inside_function)
my_function(x = 2)

After you find an error, don’t forget to stop observing the function:

undebug(my_inside_function)

You can also use debugonce(), the name of which is rather self-explanatory.

A quick view of where the bug may come from.

(from R docs)

Our example code:

foo <- function(x) { print(1); bar(2) }
bar <- function(x) { x + a.variable.which.does.not.exist }
foo(2)
## [1] 1
## Error in bar(2): object 'a.variable.which.does.not.exist' not found

produces a strange error.

traceback()
## End(Not run)
## 2: bar(2)
## 1: foo(2)

As you can see, traceback() immediately points at the line where the error occured.

There are two other functions that may be used for debugging, but as they are rarely used, I will not describe them in detail.