CS 307: Debugging
Debugging programs is an important skill for a computer scientist.
Here are some hints about debugging:
- Document clearly what each function should do. Write a comment
(after a semicolon) that states what the function does.
Write a comment describing each argument, unless it is obvious.
Write a comment with an example of a call to the function.
; Compute the value of an investment of a fixed contribution for a
; given number of time periods at a specified interest rate.
; contribution = amount added at the end of a time period
; time = number of time periods
; interest = interest paid per time period, e.g. 6% = 0.06
; Example: (invest 1040 60 0.06) ; $1040 per year for 60 years at 6%
(define (invest contribution time interest) ...)
These comments are a specification of your program.
One source of bugs is an unclear (poorly understood, unwritten) specification.
Sometimes, a clear specification will make it obvious how to write the
program. One of the best ways to debug is not to write bugs; a good
- Test the function on an easy case first. Often, the easy case is
the base case of a recursive function. Make sure the answer is correct
for the easy case. Then try a slightly harder case -- one for which
you understand the answer.
> (invest 100 0 0.06)
> (invest 100 1 0.06)
> (invest 100 2 0.06)
Investing $100 zero times gives zero. Investing $100 at the end of one time
period leaves us with the given $100. Investing $100 for two time periods
gives us interest of $6 on $100 during the second time period.
If your function works on the base case and a few more cases, it probably
works for all cases; if not, it will be easier to understand and fix the
function when the case is an easy one.
- Trace your functions. Use (trace fn ) to
trace the function fn. You can turn off a trace with
The trace will show the arguments of a function on entry and the result on
exit. The entry and exit are matched by vertical alignment of the trace
- As soon as you see a bug, track it down and fix it.
Develop a keen eye for anything that looks unusual in your output; if
you see something abnormal, focus on it.
- Test your functions one at a time.
This is easy in Lisp: simply type in a call to a function
with test arguments, even if it is not the ``main'' function.
It is easy to test a single function in isolation, but hard to test a
- Use rapid prototyping and evolve your programs:
write a program that does part of the job, test it, then expand it.
When you get part of the program working, you can expand
on that model; this is better than repeating the same mistake many times
in your code before doing any testing.
- If your program ``cannot possibly be doing what it is doing'',
the bug is probably something that you are not looking at. Take a wider
view and look at other things.
- Instrument your code with debugging printouts: print out internal values
and look for abnormalities. Sometimes students stay up all night trying
to reason about why their program does not work, when a simple printout
would make the problem obvious.
You can detect internal errors and stop your program (and then get variable
values) using an (error   "message") call.
(error "The elusive bug has occurred!"))
- When you get an error break, DrScheme can provide additional information:
- Click the function name to get instant documentation of the
function in which the error occurred.
- Click the Bug symbol to get backtrace information.
This will show the sequence of calls that reached the error and