---
title: "Debugging Basics"
author: "Statistical Computing, 36-350"
date: "Monday October 17, 2016"
---

Bug!
===

The original name for glitches and unexpected defects: dates back to at least Edison in 1876, but better story from Grace Hopper in 1947:

![](https://upload.wikimedia.org/wikipedia/commons/8/8a/H96566k.jpg)
(From Wikipedia)

Debugging: what and why?
===

Debugging is a the process of locating, understanding, and removing bugs from your code

Why should we care to learn about this?

- The truth: you're going to have to debug, because you're not perfect (none of us are!) and so you can't write perfect code
- Debugging is frustrating and time-consuming, but essential
- Writing code that makes it easier to debug later is worth it, even if it takes a bit more time (lots of our design ideas support this)
- Simple things you can do to help: use lots of comments, use meaningful variable names!

Debugging: how?
===

Debugging is (largely) a process of differential diagnosis. Stages of debugging:

0. Reproduce the error: can you make the bug reappear?
1. Characterize the error: what can you see that is going wrong?
2. Localize the error: where in the code does the mistake originate?
3. Modify the code: did you eliminate the error? Did you add new ones?


Reproduce the bug
===

Step 0: make if happen again

- Can we produce it repeatedly when re-running the same code, with the same input values? 
- And if we run the same code in a clean copy of R, does the same thing happen?

Characterize the bug
===

Step 1: figure out if it's a pervasive/big problem

- How much can we change the inputs and get the same error?
- Or is it a different error?
- And how big is the error? 

Localize the bug
===

Step 2: find out exactly where things are going wrong

- This is most often the hardest part!
- Today, we'll learn how to understand errors, using `traceback()`, and also `cat()`, `print()`
- Next time, we'll learn how to interactively debug with the R tool `browser()`

Localizing can be easy or hard
===

Sometimes error messages are easier to decode, sometimes they're harder; this can make locating the bug easier or harder

```{r, error=TRUE}
my.plotter = function(x, y, my.list=NULL) {
  if (!is.null(my.list)) 
    plot(my.list, main="A plot from my.list!")
  else
    plot(x, y, main="A plot from x, y!")
}

my.plotter(x=1:8, y=1:8)
my.plotter(my.list=list(x=-10:10, y=(-10:10)^3))
my.plotter() # Easy to understand error message
my.plotter(my.list=list(x=-10:10, Y=(-10:10)^3)) # Not as clear
```

Who called `xy.coords()`? (Not us, at least not explicitly!) And why is it saying 'x' is a list? (We never set it to be so!)

`traceback()`
===

A call to `traceback()`, after an error: traces back through all the function calls leading to the error

- Start your attention at the "bottom", where you recognize the function you called
- Read your way up to the "top", which is the lowest-level function that produces the error
- Often the most useful bit is somewhere in the middle

If you ran the last example `my.plotter(my.list=list(x=-10:10, Y=(-10:10)^3))` in the console, then called `traceback()`, you'd see:

```
> traceback()
5: stop("'x' is a list, but does not have components 'x' and 'y'")
4: xy.coords(x, y, xlabel, ylabel, log)
3: plot.default(my.list, main = "A plot from my.list!")
2: plot(my.list, main = "A plot from my.list!") at #4
1: my.plotter(my.list = list(x = -10:10, Y = (-10:10)^3))
```

We can see that `my.plotter()` is calling `plot()` is calling `plot.default()` is calling `xy.coords()`, and this last function is throwing the error

Why? Its first argument `x` is being set to `my.list`, which is OK, but then it's expecting this list to have components named `x` and `y` (ours are named `x` and `Y`)

`cat()`, `print()`
===

You can modify your function by calling `cat()` or `print()` at various points, to print out the state of variables, to help you localize the error

```{r}
my.plotter = function(x, y, my.list=NULL) {
  if (!is.null(my.list)) {
    print("Here is my.list:")
    print(my.list)
    print("Now about to plot my.list")
    plot(my.list, main="A plot from my.list!")
  }
  else {
    print("Here is x:"); print(x)
    print("Here is y:"); print(y)
    print("Now about to plot x, y")
    plot(x, y, main="A plot from x, y!")
  }
}
```

(Continued)
===

Here it's not exactly critical to use `print()` for debugging, but this is just a demonstration of how we might check the status of variables along the way

```{r, error=TRUE}
my.plotter(my.list=list(x=-10:10, Y=(-10:10)^3))
my.plotter(x="hi", y="there")
```
