<HTML> <HEAD> <TITLE>Computer Science Logo Style vol 1 ch 15: Debugging</TITLE> </HEAD> <BODY> <CITE>Computer Science Logo Style</CITE> volume 1: <CITE>Symbolic Computing</CITE> 2/e Copyright (C) 1997 MIT <H1>Debugging</H1> <TABLE width="100%"><TR><TD> <IMG SRC="../csls1.jpg" ALT="cover photo"> <TD><TABLE> <TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian Harvey</A><BR>University of California, Berkeley</CITE> <TR><TD align="right"><BR> <TR><TD align="right"><A HREF="../pdf/v1ch15.pdf">Download PDF version</A> <TR><TD align="right"><A HREF="../v1-toc2.html">Back to Table of Contents</A> <TR><TD align="right"><A HREF="../v1ch14/v1ch14.html"><STRONG>BACK</STRONG></A> chapter thread <A HREF="../v1ch16/versions.html"><STRONG>NEXT</STRONG></A> <TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-1">MIT Press web page for Computer Science Logo Style</A> </TABLE></TABLE> <HR> <P> I haven't talked much, until now, about how to find and fix mistakes in the programs you write. Except for the chapter-length examples in Chapters 6, 12, and 14, it hasn't been much of a problem because the sample programs I've shown you have been so small. That doesn't mean you can't make a mistake in a small program! But mistakes are relatively easy to find when the entire program is one procedure with just a few instruction lines. In a real programming project, which might have 20 or 200 procedures, it's harder to locate an error. <P><H2>Using Error Messages</H2> <P>At one point in Chapter 13 I saw the error message <P><PRE>I don't know how to one in pokerhand </PRE> <P>Logo's error messages were deliberately designed to use an informal, smooth, low-key style so that beginning programmers won't find them intimidating. But there is a lot of information in that message if you learn how to find it. The message tells me three things. First, it tells me what <EM>kind</EM> of error is involved. In this particular message, the phrase "I don't know how" suggests that a procedure is missing, and the words "to one" subtly suggest how the problem could be fixed. Second, the message tells me the <EM>specific</EM> expression that was in error: the word <CODE>one</CODE>. Third, it tells me that the error was detected while Logo was carrying out the procedure named <CODE> pokerhand</CODE>. <P>The precise form of the message may be different in different situations. If you make a mistake in a top-level instruction (that is, one that you type to a question mark prompt, not inside a procedure), the part about <CODE>in pokerhand</CODE> won't be included. <P>One very important thing to remember is that the place where an error is <EM>found</EM> may not be the place where the error really <EM> is.</EM> That's a little vague, so let's think about the <CODE>I don't know how</CODE> error. All the Logo interpreter knows is that it has been asked to invoke a procedure that doesn't exist. But there can be several possible reasons for that. The most common reason is that you've just misspelled the name of a procedure. When the message is <P><PRE>I don't know how to forwrad in poly </PRE> <P>you can be pretty sure, just from reading the message, that the problem is a misspelling of <CODE>forward</CODE>. In this case the mistake is in <CODE>poly</CODE>, just as the message tells you. <P>On the other hand you might get a message like this about a procedure that really should exist. For example, I might have seen <P><PRE>I don't know how to straight in pokerhand </PRE> <P>If I had been confronted with that message, I might have looked at <CODE>pokerhand</CODE>, and indeed I would have found an instruction that invokes a procedure named <CODE>straight</CODE>. But that's not an error; there <EM>should</EM> be such a procedure. One of two things would be wrong: either I'd forgotten to define <CODE> straight</CODE> altogether or else I made a spelling mistake in the title line of <CODE>straight</CODE> rather than in an instruction line of <CODE> pokerhand</CODE>. To find out, I would type the command <CODE>pots</CODE> (which, as you recall, stands for Print Out TitleS) and look for a possible misspelling of <CODE>straight</CODE>. <P>Another way to get the same error message is to write a program using one version of Logo and then transfer it to another version with somewhat different primitives. For example, Berkeley Logo includes higher order functions such as <CODE>map</CODE> that are not primitive in most other Logo dialects. If you write a program that uses <CODE>map</CODE> and then try to run it in another version of Logo, you'll get a message saying <CODE>I don't know how to map</CODE>. In that case you'd have to write your own version of <CODE> map</CODE> or rewrite the program to avoid using it--for example, by using a recursive operation instead. <P>The mistake I actually made in Chapter 13 wasn't a misspelling, a missing definition, or a nonexistent primitive. Instead, I failed to quote a list with square brackets. The particular context in which I did it, in an input to <CODE>ifelse</CODE>, is a fairly obscure one. But here is a common beginner's mistake, especially for people who are accustomed to other programming languages: <P><PRE>? <U>print "How are you?"</U> How i don't know how to are </PRE> <P>The moral of all this is that the error message <EM>does</EM> give you some valuable help in finding your bug, but it <EM>doesn't</EM> tell you the whole story. You have to read the message intelligently. <P><H2>Invalid Data</H2> <P>I've spent a lot of time on the <CODE>I don't know how</CODE> message because it's probably the most common one. Another very common kind of message, which will merit some analysis here, is <P><PRE><U>procedure</U> doesn't like <U>datum</U> as input </PRE> <P>In general, this means that you've violated the rules about the kinds of data that some primitive procedure requires as input. (Recall that the type of input is one of the things I've been insisting that you mention as part of the description of a procedure.) For example, <CODE>word</CODE> requires words as inputs, so: <P><PRE>? <U>print word "hello, [old buddy]</U> word doesn't like [old buddy] as input </PRE> <P>There are several special cases, however, that come up more often than something as foolish as using a list as an input to <CODE>word</CODE>. The most common message of this form is this one: <P><PRE>butfirst doesn't like [] as input </PRE> <P>This almost invariably means that you've left out the stop rule in a recursive procedure. The offending input to <CODE>butfirst</CODE> isn't an explicit empty list but instead is the result of evaluating a variable, usually an input to the procedure you're writing, that's <CODE>butfirst</CODE>ed in the recursive invocation. This is a case where the error isn't really in the instruction that caused the message. Usually there is nothing wrong with the actual invocation of <CODE>butfirst</CODE>; the error is a missing instruction earlier in the procedure. If the input is a word instead of a list, this message will take the possibly confusing form <P><PRE>butfirst doesn't like as input </PRE> <P>That's an invisible empty word between <CODE>like</CODE> and <CODE> as</CODE>! <P>I said that this message is almost always caused by a missing stop rule. You have to be careful about the "almost." For example, recall this practical joke procedure from Chapter 1: <P><PRE>to process :instruction test emptyp :instruction iftrue [type "|? | process readlist stop] iffalse [print sentence [|I don't know how to|] first :instruction] end </PRE> <P>This is not a recursive procedure, and the question of stop rules doesn't arise. But its input might be empty, because the victim enters a blank line. If I hadn't thought of that, and had written <P><PRE>to process :instruction print sentence [|I don't know how to|] first :instruction end </PRE> <P>the result would be <P><PRE>first doesn't like [] as input in process </PRE> <P>Another case that sometimes comes up in programs that do arithmetic is <P><PRE>/ doesn't like 0 as input </PRE> <P>For example, if you write a program that takes the average of a bunch of numbers and you try to use the program with an empty list of numbers as input, you'll end up trying to divide zero by zero. The solution is to insert an instruction that explicitly tests for that possibility. <P>As always, the procedure that provokes the error message may not actually be the procedure that is in error. Consider this short program: <P><PRE>to second :thing output first butfirst :thing end to swap :list output list (second :list) (first :list) end ? <U>print swap [watch pocket]</U> pocket watch ? <U>print swap [farewell]</U> first doesn't like [] as input in second [output first butfirst :thing] </PRE> <P>Although the error was caught during the invocation of <CODE> second</CODE>, there is nothing wrong with <CODE>second</CODE> itself. The error was in the top-level instruction, which provided a bad input to <CODE> swap</CODE>. That instruction doesn't even include an explicit reference to <CODE>second</CODE>. In this small example it's easy to see what happened. But in a more complicated program it can be hard to find errors like this one. <P>There are two ways you can protect yourself against this kind of difficulty. The first is <EM>defensive programming.</EM> I could have written the program this way: <P><PRE>to swap :list if emptyp :list [pr [empty input to swap] stop] if emptyp butfirst :list [pr [singleton input to swap] stop] output list (second :list) (first :list) end </PRE> <P>This version checks for bad inputs and gives a more helpful error message.*Actually, when you invoke this version of <CODE>swap</CODE> with a bad input, you'll see <EM>two</EM> error messages. The procedure itself will print an error message. Then, since it <CODE> stop</CODE>s instead of <CODE>output</CODE>ting something to its superprocedure, you'll get a <CODE>didn't output</CODE> error message from the Logo interpreter. It would also be possible to figure out an appropriate output for these cases and not consider them errors at all: <P><PRE>to swap :list if emptyp :list [output []] if emptyp butfirst :list [output :list] output list (second :list) (first :list) end </PRE> <P>This version manages to produce an output for any input at all. How should you choose between these two defensively written versions? It depends on the context in which you'll be using <CODE> swap</CODE>. If you are writing a program in which <CODE>swap</CODE> should always get a particular kind of list as input, which should always have two members, then you should use the first defensive version, which will let you know if you make an error in the input to <CODE>swap</CODE>. But if <CODE>swap</CODE> is intended as a general tool, which might be used in a variety of situations, it might be better to accept any input. <P>The second protective technique, besides defensive programming, is tracing, the technique we used in Chapter 9. If you get an error message from a utility procedure like <CODE>second</CODE> and you have no idea how it was invoked, you can find out by tracing the entry into all of your procedures. <P>Another way to get the <CODE>doesn't like</CODE> message is to forget the order of inputs to a procedure, either a primitive or one that you've written. For example, <CODE>lput</CODE> is a primitive operation that requires two inputs. The first input can be any datum, but the second must be a list. The output from <CODE>lput</CODE> is a list that contains all the members of the second input, plus one more member at the end equal to the first input. <P><PRE>? <U>show lput "c [a b]</U> [a b c] </PRE> <P><CODE>Lput</CODE> takes its inputs in the same order as <CODE>fput</CODE>, with the new member first and then the old list. But you might get confused and want the inputs to appear left-to-right as they appear in the result: <P><PRE>? <U>show lput [a b] "c</U> lput doesn't like c as input </PRE> <P><H2>Incorrect Results</H2> <P>Beginning programmers are often dismayed when they see an error message, but more experienced programmers are relieved. They know that the bugs that cause such messages are the easy ones to find! Much harder are the bugs that allow a program to run to completion but produce the wrong answer. In that kind of situation you don't have the advantage of knowing which procedure tickled the error message, so it's hard to know where to begin looking. <P>Here's a short program with a couple of bugs in it. <CODE>Arabic</CODE> is an operation that takes one input, a word that is a Roman numeral. The output from <CODE>arabic</CODE> is the number represented by that Roman numeral in ordinary (Arabic numeral) notation. <P><PRE>to arabic :num output addup map "digit :num end to digit :digit output lookup :digit [[I 1] [V 5] [X 10] [L 50] [C 100] [D 500] [M 1000]] end to lookup :word :dictionary if emptyp :dictionary [output "] if equalp :word first first :dictionary [output last first :dictionary] output lookup :word bf :dictionary end to addup :list if emptyp :list [output 0] if emptyp bf :list [output first :list] if (first :list) < (first bf :list) ~ [output sum ((first bl :list)-(first :list)) addup bf bf :list] output sum first :list addup bf :list end </PRE> <P><CODE>Arabic</CODE> uses two non-primitive subprocedures, dividing its task into two parts. First <CODE>digit</CODE> translates each letter of the Roman numeral into the number it represents: <CODE>C</CODE> into 100, <CODE>M</CODE> into 1000. The result is a list of numbers. Then <CODE>addup</CODE> translates that list into a single number, adding or subtracting each member as appropriate. The rule is that the numbers are added, except that a smaller number that appears to the left of a larger one is subtracted from the total. For example, in the Roman numeral <CODE>CLIV</CODE> all the letters are added except for the <CODE>I</CODE>, which is to the left of the <CODE>V</CODE>. Since <CODE>I</CODE> represents 1 and <CODE>V</CODE> represents 5, and 1 is less than 5, the <CODE>I</CODE> is subtracted. The result is 100+50+5-1 or 154. <P>Here's what happened the first time I tried <CODE>arabic</CODE>: <P><PRE>? <U>print arabic "MLXVI</U> 13 </PRE> <P>This is a short enough program that you may be able to find the bug just by reading it. But even if you do, let's pretend that you don't, because I want to use this example to talk about some ways of looking for bugs systematically. <P>The overall structure of the program is that <CODE>digit</CODE> is invoked for each letter, and the combined output from all the calls to <CODE>digit</CODE> is used as the input to <CODE>addup</CODE>. The first step is to try to figure out which of the two is at fault. Which should we try first? Since <CODE>addup</CODE> depends on the work of <CODE>digit</CODE>, whereas <CODE>digit</CODE> doesn't depend on <CODE> addup</CODE>, it's probably best to start with <CODE>digit</CODE>. So let's try looking at the output from <CODE>digit</CODE> directly. <P><PRE>? <U>print digit "M</U> 1000 ? <U>print digit "V</U> 5 </PRE> <P>So far so good. Perhaps the problem is in the way <CODE>map</CODE> is used to combine the results from <CODE>digit</CODE>: <P><PRE>? <U>show map "digit "MLXVI</U> 1000501051 </PRE> <P>Aha! I wanted a list of numbers, one for each Roman digit, but instead I got all the numbers combined into one long word. I had momentarily forgotten that if the second input to <CODE>map</CODE> is a word, its output will be a word also. As soon as I see this, the solution is apparent to me: I should use <CODE>map.se</CODE> instead of <CODE>map</CODE>. <P><PRE>? <U>show map.se "digit "MLXVI</U> [1000 50 10 5 1] to arabic :num output addup map.se "digit :num end ? <U>print arabic "MLXVI</U> 1066 </PRE> <P>This time I got the answer I expected. On to more test cases: <P><PRE>? <U>print arabic "III</U> 3 ? <U>print arabic "XVII</U> 17 ? <U>print arabic "CLV</U> 155 ? <U>print arabic "CLIV</U> 150 ? </PRE> <P>Another error! The result was 150 instead of the correct 154. Since the other three examples are correct, the program is not completely at sea; it's a good guess that the bug has to do with the case of subtracting instead of adding. Trying a few more examples will help confirm that guess. <P><PRE>? <U>print arabic "IV</U> 0 ? <U>print arabic "MCM</U> 1000 ? <U>print arabic "MCMLXXXIV</U> 1080 ? <U>print arabic "MDCCLXXVI</U> 1776 ? </PRE> <P>Indeed, numbers that involve subtraction seem to fail, while ones that are purely additive seem to work. If you look carefully at exactly <EM>how</EM> the program fails, you may notice that the letter that should be subtracted and the one after it are just ignored. So in the numeral <CODE>MCMLXXXIV</CODE>, which represents 1984, the <CODE>CM</CODE> and the <CODE>IV</CODE> don't contribute to the program's result. <P>Once again, we must find out whether the bug is in <CODE>digit</CODE> or in <CODE> addup</CODE>, and it makes sense to start by checking the one that's called first. (If you read the instructions in the definitions of <CODE>digit</CODE> and <CODE> addup</CODE>, you'll see that <CODE>digit</CODE> handles each digit in isolation, whereas <CODE>addup</CODE> is the one that looks at two consecutive digits to decide whether or not to subtract. But at first I'm not reading the instructions at all; I'm trying to be sure that I understand the <EM>behavior</EM> of each procedure before I look inside any of them. For a simple problem like this one, the approach I'm using is more ponderous than necessary. But it would pay off for a larger program with more subtle bugs.) <P><PRE>? <U>show map.se "digit "VII</U> [5 1 1] ? <U>show map.se "digit "MDCCLXXVI</U> [1000 500 100 100 50 10 10 5 1] </PRE> <P>I've started with Roman numerals for which the overall program works. Why not just concentrate on the cases that fail? Because I want to see what the <EM>correct</EM> output from <CODE>map</CODE>ping <CODE>digit</CODE> over the Roman numeral is supposed to look like. It turns out to be a list of numbers, one for each letter in the Roman numeral. <P>You may wonder why I need to investigate the correct behavior of <CODE> digit</CODE> experimentally. If I've planned the program properly in the first place, I should <EM>know</EM> what it's supposed to do. There are several reasons why I might feel a need for this sort of experiment. Perhaps it's someone else's program I'm debugging, and I don't know what the plan was. Perhaps it's a program I wrote a long time ago and I've forgotten. Finally, since there is a bug after all, perhaps my understanding is faulty even if I do think I know what <CODE>digit</CODE> is supposed to do. <P>Now let's try <CODE>digit</CODE> for some of the buggy cases. <P><PRE>? <U>show map.se "digit "IV</U> [1 5] ? <U>show map.se "digit "MCMLXXXIV</U> [1000 100 1000 50 10 10 10 1 5] ? </PRE> <P><CODE>Digit</CODE> still does the right thing: It outputs the number corresponding to each letter. The problem must be in <CODE>addup</CODE>. <P>Now it's time to take a look at <CODE>addup</CODE>. There are four instructions in its definition. Which is at fault? It must be one that comes into play only for the cases in which subtraction is needed. That's a clue that it will be one of the <CODE>if</CODE> instructions, although instructions that aren't explicitly conditional can, in fact, depend on earlier <CODE>if</CODE> tests. (In this procedure, for example, the last instruction doesn't look conditional. But it is carried out only if none of the earlier instructions results in an <CODE>output</CODE> being evaluated.) <P>Rather than read every word of every line carefully, we should start by knowing the purpose of each instruction. The first one is an end test, detecting an empty numeral. The second is also an end test, detecting a single-digit numeral. (Why are two end tests necessary? How would the program fail if each one were eliminated?) The third instruction deals with the subtraction case, and the fourth with the addition case. The bug, then, is probably in the third instruction. Here it is again: <P><PRE>if (first :list) < (first bf :list) ~ [output sum ((first bl :list)-(first :list)) addup bf bf :list] </PRE> <P>At this point a careful reading of the instruction will probably make the error obvious. If not, look at each of the expressions used within the instruction, like <P><PRE>first :list </PRE> <P>and <P><PRE>bf bf :list </PRE> <P>What number or list does each of them represent? <P>(If you'd like to take time out for a short programming project now, you might try writing <CODE>roman</CODE>, an operation to translate in the opposite direction, from Arabic to Roman numerals. The rules are that <CODE>I</CODE> can be subtracted from <CODE>V</CODE> or <CODE>X</CODE>; <CODE>X</CODE> can be subtracted from <CODE>L</CODE> or <CODE>C</CODE>; and <CODE>C</CODE> can be subtracted from <CODE>D</CODE> or <CODE>M</CODE>. You should never need to repeat any symbol more than three times. For example, you should use <CODE>IV</CODE> rather than <CODE>IIII</CODE>.) <P><H2>Tracing and Stepping</H2> <P>In Chapter 9 we used the techniques of <EM>tracing</EM> and <EM> stepping</EM> to help you understand how recursive procedures work. The same techniques can be very valuable in debugging. Tracing a procedure means making it print an indication of when it starts and stops. Stepping a procedure means making it print each of its instructions and waiting for you to type something before evaluating the instruction. <P>Berkeley Logo provides primitive commands <CODE>trace</CODE> and <CODE>step</CODE> that automatically trace or step procedures for you. <CODE> Trace</CODE> and <CODE>step</CODE> take one input, which can be either a word or a list. If the input is a word, it must be the name of a procedure. If a list, it must be a list of words, each of which is the name of a procedure. The effect of <CODE>trace</CODE> is to modify the procedure or procedures named in the input to identify the procedure and its inputs when it is invoked. The effect of <CODE>step</CODE> is to modify the named procedure(s) so that each instruction is printed before being evaluated. <P>Tracing a procedure is particularly useful in the annoying situation in which a program just sits there forever, never stopping, but never printing anything either. This usually means that there is an error in a recursive procedure, which invokes itself repeatedly with no stop rule or with an ineffective one. If you trace recursive procedures, you can find out how you got into that situation. <P> <H2>Pausing</H2> <P>When a program fails, either with an error message or by printing the wrong result, it can be helpful to examine the values of the variables used within the program. Of course, you understand by now that "the variables used within the program" may be a complicated idea; if there are recursive procedures with local variables, there may be several variables with the same name, one for each invocation of a procedure. <P>Once a program is finished running, the local variables created by the procedures within the program no longer exist. You can examine global variables individually by <CODE>print</CODE>ing their values or all at once with the <CODE>pons</CODE> command. (<CODE>Pons</CODE> stands for Print Out NameS; it takes no inputs and prints the names and values of all current variables.) But it's too late to examine local variables after a program stops. <P>To get around this problem, Berkeley Logo provides a <CODE>pause</CODE> command. This command takes no inputs. Its effect is to stop, temporarily, the procedure in which it appears. (Like <CODE>stop</CODE> and <CODE>output</CODE>, <CODE>pause</CODE> is meaningless at top level.) Logo prints a question mark prompt (along with the name of the paused procedure to remind you that it's paused), and you can enter instructions to be evaluated as usual. But the paused procedure is <EM>still active;</EM> its local variables still exist. (Any superprocedures of the paused procedure, naturally, are also still active.) The instructions you type while the procedure is paused can make use of local variables, just as if the instructions appeared within the procedure definition. <P>The main use of <CODE>pause</CODE> is for debugging. If your program dies with an error message you don't understand, you can insert a <CODE> pause</CODE> command just before the instruction that gets the error. Then you can examine the variables that will be used by that instruction. <P>Better yet, you can ask Logo to pause <EM>automatically</EM> whenever an error occurs. In fact, you can ask Logo to carry out any instructions you want, whenever an error occurs, by creating a variable named <CODE>erract</CODE> (short for error action) whose value is an instruction list. If you want your program to pause at any error, say <P><PRE>? <U>make "erract [pause]</U> </PRE> <P>before you run the program. To undo this request, you can erase the variable name <CODE>erract</CODE> with the <CODE>ern</CODE> (erase name) command: <P><PRE>? <U>ern "erract</U> </PRE> <P>Once you've examined the relevant variables, you may want to continue running the program. You'll certainly want to continue if this pause wasn't the one you're waiting for, just before the error happens. Logo provides the command <CODE>continue</CODE> (abbreviated <CODE>co</CODE>) for this purpose. If you type <CODE>continue</CODE> with no input, Logo will continue the evaluation of the paused procedure where it left off. <P>It is also possible to use <CODE>continue</CODE> with an input, turning the <CODE>pause</CODE> command into an operation by providing a value for it to output. Whether or not that's appropriate depends on which error message you get. If the message complains about a missing value, you may be able to provide one to allow the program to continue: <P><PRE>to demo.error print first :nonesuch end ? <U>make "erract [pause]</U> ? <U>demo.error</U> nonesuch has no value in demo.error [print first :nonesuch] Pausing... demo.error? <U>continue "hello</U> h </PRE> <P>If, after examining variables, you figure out the reason for the bug, you may not want to bother continuing the buggy procedure. Instead you'll want to forget about it, edit the definition to fix the bug, and try again. But you shouldn't just forget about it because the procedure is still active. If you don't want to continue it, you should <CODE>stop</CODE> it instead, to get back to the "real" top level with no procedures active. (Instead of <CODE>stop</CODE>, a more definitive way to stop all active procedures is with the instruction <P><PRE>throw "toplevel </PRE> <P>For now just think of this as a magic incantation; we'll talk more about <CODE>throw</CODE> in the second volume.) <P>Berkeley Logo also has a special character that you can type on the keyboard to cause an immediate pause. The character depends on which computer you're using; see Appendix A. This is not as useful a capability as you might think because it's hard to synchronize your typing with the activity of the program so that it gets paused in the right <EM> context</EM> (that is, with the right procedures active and the right local variables available). But it can be useful if you can see that the program is repeating the same activities over and over, for example; pausing just about anywhere during that kind of <EM>loop</EM> is likely to give you useful information. <P><H2>Final Words of Wisdom</H2> <P>You may be feeling a frustrating sense of incompleteness about this chapter. After the chapter on variables, for example, you really knew everything there is to know about variables. (I suppose that's not strictly true, since you hadn't thought about recursion yet, but it's true enough.) But you certainly don't know everything there is to know about debugging. That's because there isn't a complete set of rules that will get you through every situation. You just have to do a lot of programming, meet a lot of bugs, and develop an instinct for them. <P>As a beginner, you'll probably meet bugs with a different flavor from the ones I've been discussing. You'll put a space after a quotation mark or a colon, before the word to which it should be attached. You'll leave out a left or right parenthesis or bracket. (Perhaps you'll get confused about when to use parentheses and when brackets!) All of these simple errors will quickly get you error messages, and you can probably find your mistake just by reading the offending instruction. Later, as your programs get more complicated, you'll start having the more interesting bugs that require analysis to find and fix. <P>It's a good idea to program with a partner. Sometimes you can find someone else's bugs more easily than your own--when you read your own program, you know too well what you <EM>meant</EM> to say. This advice is not just for beginners; even experienced programmers often benefit from sharing their bugs with a friend. Another advantage of such a partnership is that trying to explain your program to someone else will often help you understand it more clearly yourself. I've often discovered a persistent bug halfway through explaining the problem to someone. <P>The main point, I think, is one I've made in earlier chapters: there is nothing shameful about a bug in your program. As a teacher, I've been astonished to see students react to a simple bug by angrily erasing an entire program, which they'd spent hours writing! Teach yourself to expect bugs and approach them with a good-natured spirit. <P>On the other hand, you can minimize your debugging time by writing the program in a reasonable style in the first place. If your program is one long procedure, you should know that you're making it harder to locate an offending instruction. If all your variables are named <CODE> x</CODE> and <CODE>y</CODE>, you deserve whatever happens to you! And if you can't figure out, yourself, which procedure does what, then perhaps you should stop typing in procedures and spend a little time with paper and pencil listing the tasks each procedure needs to carry out. <P><A HREF="../v1-toc2.html">(back to Table of Contents)</A> <P><A HREF="../v1ch14/v1ch14.html"><STRONG>BACK</STRONG></A> chapter thread <A HREF="../v1ch16/versions.html"><STRONG>NEXT</STRONG></A> <P> <ADDRESS> <A HREF="../index.html">Brian Harvey</A>, <CODE>bh@cs.berkeley.edu</CODE> </ADDRESS> </BODY> </HTML>