Introduction to Debugging in R, List of R Debugging Functions


1. Objective

In this R tutorial, we are going to discuss the very interesting topic i.e. R Debugging. Here we will discuss What is Debugging, What is the fundamental principle of Debugging in R programming. We will also cover the different functions for Debugging in R with the help of examples in this R programming tutorial.

What is Debugging in R Programming?

2. What is Debugging?

A grammatically correct program may give us incorrect results due to logical errors. In case, if such errors (i.e. bugs) occur, we need to find out why and where they occur so that you can fix them. The procedure to identify and fix bugs is called “debugging”.

R provides a number of functions for debugging, such as:

  • traceback()
  • debug()
  • browser()
  • trace()
  • recover()

We will discuss the above-mentioned functions one-by-one in the later section of this blog.

3. Fundamental Principles of Debugging

Programmers often find that they spend more time debugging a program than actually writing it. Good debugging skills are invaluable.

3.1. The essence of debugging: The principle of confirmation

Fixing a bugging program is a process of confirming, one by one, that the many things you believe to be true about code actually are true. When we find one of our assumptions is not true, we have found a clue to the location of a bug.

For Example:

x <- y^2 + 3*g(z, 2)

w <- 28

if (w+q > 0) u <- 1 else v <- -10

3.2. Start Small

At least at the beginning of the debugging process, stick to small simple test cases. Working with large data objects may make it harder to think about the problem. Of course, we should eventually test our code in large, complicated cases, but start small.

3.3. Debug in a Modular, Top-Down Manner

Most good software developers agree that code should be written in a modular manner. Our first-level code should not be long with much of it consisting of functions calls. And those functions should not be too lengthy and should call another function if necessary. This makes code easier at the writing stage and also easier for others to understand when it comes time for the code to be extended.

We should debug in a top-down manner, too. Suppose we have a set the debug status of our function

f() and f() contains this line.

For Example:

Y <- g(x,8)

Do not call debug (g) yet. Execute that line and see g() returns the value we expect. If it does then we have to just avoid the time-consuming process of single-stepping Through g(). If g() returns the wrong value, then now is the time to call debug(g).

3.4. Antibugging

If we have a section of a code in which a variable x should be positive. We can insert this line:

Stopifnot(x>0)

If there is a bug earlier in the code that renders x equals to, say -3, the call to stopifnot() will bring things right there, with an error message like this:

Error: x > 0 is not TRUE

4. Functions for Debugging in R Programming

Now we will discuss the above-mentioned functions for debugging in R.

4.1. traceback()

If our code has already crashed and we want to know where the offending line is, try traceback(). This will (sometimes) show where abouts in the code the problem occurred.

When an R function fails, an error is printed to the screen. Immediately after the error, you can call traceback() to see in which function the error occurred. The traceback() function prints the list of functions that were called before the error occurred. The functions are printed in reverse order.

For Example:

f<-function(x) {
r<-x-g(x)
r
}
g<-function(y) {
r<-y*h(y)
r
}
h<-function(z) {
r<-log(z)
if(r<10)
r^2
else
r^3
}
> f(-1)
Error in if (r < 10) r^2 else r^3: missing value where TRUE/FALSE needed
In addition: Warning message:
In log(z) : NaNs produced
> traceback()
3: h(y)
2: g(x)
1: f (-1)

4.2. debug()

The function debug() allows one to step through the execution of a function, line by line. At any point, we can print out values of variables or produce a graph of the results within the function. While debugging, we can simply type “c” to continue to the end of the current section of code. traceback() does not tell us where in the function the error occurred. In order to know which line causes the error, we may want to step through the function using debug().

For Example:

Compute the sum of squared error SS = ∑ni=1(xi−μ)

## compute sum of squares
SS<-function(mu,x) {
d<-x-mu
d2<-d^2
ss<-sum(d2)
ss
}
# set seed to get reproducible results
> set.seed(100)
> x<-rnorm(100)
> SS(1,x)
[1] 202.5615
## now start debugging
> debug(SS)
> SS(1,x)
debugging in: SS(1, x)
debug: {
d <- x - mu
d2 <- d^2
ss <- sum(d2)
ss
}
attr(,"srcfile")
C:\Users\jihk\doc\courses\StatisticalComputing\lecture5\debugex2.R
Browse[1]>

After you see the “Browse[1]>” prompt, you can do different things:

  • Typing n executes the current line and prints the next one;
  • By typing Q, we can quit the debugging;
  • Typing where tells where you are in the function call stack;
  • By typing ls(), we can list all objects in the local environment;

Typing an object name or print(<object name>) tells us current value of the object. If your object has name n, c or Q, we have to use print() to see their values.

4.3. browser()

The function browser() stops the execution of a function until the user allows it to continue. This is useful if we don’t want to step through all the code, line-by-line, but we want it to stop at a certain point so we can check out what is going on. Inserting a call to the browser() in a function will pause the execution of a function at the point where the browser() is called. Similar to using debug() except we can control where execution gets paused.

For Example:

h<-function(z) {
browser() ## a break point inserted here
r<-log(z)
if(r<10)
r^2
else
r^3
}
> f(-1)
Called from: h(y)
Browse[1]> ls()
[1] "z"
Browse[1]> z
[1] -1
Browse[1]> n
debug: r <- log(z)
Browse[1]> n
debug: if (r < 10) r^2 else r^3
Browse[1]> ls()
[1] "r" "z"
<strong>Warning message:</strong>
In log(z) : NaNs produced
Browse[1]> r
[1] NaN
Browse[1]> c
Error in if (r < 10) r^2 else r^3 : missing value where TRUE/FALSE needed
> 

3.4. trace()

Calling trace() on a function allows the user to insert bits of code into a function. The syntax for trace() is a bit strange for first time users. It might be better off using debug().

For Example:

> as.list(body(h))
[[1]]
‘{‘
[[2]]
r <- log(z)
[[3]]
if (r < 10) r^2 else r^3
attr(,"srcfile")
C:\Users\jihk\doc\courses\StatisticalComputing\lecture5\debugex1.R
> trace("h",quote(if(is.nan(r)) {browser()}), at=3, print=FALSE)
> f(1)
[1] 1
> f(-1)
Called from: eval(expr, envir, enclos)
Browse[1]> ls()
[1] "r" "z"
<strong>Warning message:</strong>
In log(z) : NaNs produced
Browse[1]> r
[1] NaN
Browse[1]> z
[1] -1
Browse[1]> c
...
>
> trace("h",quote(if(z<0) {z<-1}), at=2, print=FALSE)
[1] "h"
> f(-1)
[1] -1

4.5. recover()

When we are debugging a function, recover() allows us to check variables in upper level functions.

For Example:

> trace("h",quote(if(is.nan(r)) {recover()}), at=3, print=FALSE)
[1] "h"
> f(-1)
Enter a frame number, or 0 to exit
1: f(-1)
2: g(x)
3: h(y)
Selection: 1
Called from: eval(expr, envir, enclos)
Browse[1]> ls()
[1] "x"
Warning message:
In log(z) : NaNs produced
Browse[1]> x
[1] -1
Browse[1]> c
Enter a frame number, or 0 to exit
1: f(-1)
2: g(x)
3: h(y)
Selection: 2
Called from: eval(expr, envir, enclos)
Browse[1]> ls()
[1] "y"
Browse[1]> y
[1] -1
Browse[1]> c
Enter a frame number, or
Enter 0 to exit
1: f(-1)
2: g(x)
3: h(y)
Selection: 3
Called from: eval(expr, envir, enclos)
Browse[1]> ls()
[1] "r" "z"
Browse[1]> r
[1] NaN
Browse[1]> z
[1] -1
Browse[1]> c
Enter a frame number, or
Enter 0 to exit
1: f(-1)
2: g(x)
3: h(y)
Selection: 0
Error in if (r < 10) r^2 else r^3: missing value where TRUE/FALSE needed
  • recover() can be used as an error handler, set using options() (e.g.options(error=recover)).
  • When a function throws an error, execution is halted at the point of failure. We can browse the function calls and examine the environment to find the source of the problem.

5. Conclusion

Hence, in this tutorial, we have discussed Debugging in R along with their functions in detail with the examples. Hope you like this blog. If you have any query related to Debugging in R, so, feel free to share with us. Hope we will help you out.

See Also-

Leave a comment

Your email address will not be published. Required fields are marked *