TopTypes, againDebugging Tips

Debugging Tips

As your labs become more complicated and your knowledge of the syntax of Grace grows, you will discover that the type of errors you spend most of your time dealing with will change. The problems caused by errors involving the rules of Grace grammar will decrease and the problems caused by subtle logical difference between what you told the computer to do and what you meant to tell it will increase.

The process of removing such logical errors is called debugging. In recognition of its growing importance we want to give you four tips on how to approach it. The first two are ways to avoid complicated debugging problems in the first place, the third is a deep, guiding principle that us useful in debugging, and the last is a simple but very handy practical technique.

  1. Plan ahead.

    Having a good understanding of the problem you are trying to solve is important to successfully debug your program. We have been encouraging you to prepare for labs by outlining each different class in the code. In addition to making your lab time more productive, this practice forces you to think clearly about the problem we are asking you to solve and to explore some of the issues and potential pitfalls that will come up when you sit down in lab to write the program.

  2. Write and test your programs incrementally.

    Compile and test your code after adding small parts. Never wait until you have typed in several long methods before you start testing. This will make finding syntax errors easier, and often can give clues to potential logical errors while the problem is still reasonably small. If you do this often, you will know what you have changed recently, which helps make the next item easier.

  3. Localize the problem.

    The minute your program malfunctions, you will probably have some idea what is wrong. Suppose for example, that while you are working on writing a knitting program to draw a scarf, but the rows are not lining up nicely Demo: BadKnitting

    You might attack the problem by carefully rereading the code you have written. This is a good idea, but it is not always effective. When we write incorrect code, the error often springs from a basic misunderstanding of how our instructions will be interpreted. When we reread them, we may stick with our misunderstanding and conclude that they should work as we had intended. In order to escape our misunderstandings, we have to uncover irrefutable proof that some small section of our code is just not doing what we expected. Then, we will have to admit that something about our understanding was wrong.

    The trick is to find the small section of code that will force one to recognize the mistake quickly.

    In the case of the BadKnitting example, there are several sorts of mistakes that could cause the problem. We could have forgotten to initialize the x value properly or we might have updated it improperly or we might even have accidentally set it when we didn't want to (e.g., via a typo).

    While this program is small, in a larger program there may be an enormous number of possibilities of what could be going wrong. As long as there are so many possibilities, the debugger will tend, while looking at the code related to one possibility, to overlook the error and assume on of the other possibilities must be at fault. Narrowing things down to a single possibility is generally the best way to force oneself to admit a misunderstanding.

    This brings us to the simple technique...

  4. The use of "print"

    Consider the BadKnitting problem again. How can we narrow the search for the error down from several possibilities to just one? The answer is to try to rule out one possibility at a time.

    In this example, the easiest possibility to eliminate is the first -- it wasn't initialized properly. How can we tell if this is the case? One approach is to add another line to our program which a) will produce some visible output, and b) will be executed before the first circle is drawn.

    Producing visible output isn't too hard either. We could construct a text item, for example. But an even easier thing to do is to simply ask Grace to print a line of text. Grace has a separate pane in the editor in which such text appears. Each line displayed is just added to the bottom of the window. You don't have to specify a Location or a canvas. Thus we could write print (y) anywhere where y is defined in the program. Even through y is a number rather than a string, Grace will print the string corresponding to that number (the string is obtained by the print statement by asking for the results of the asString method).

Finally we started working on the design of the Frogger game.


TopTypes, againDebugging Tips