Computer Science Canada

Debugging

Author:  Martin [ Thu Oct 07, 2004 12:00 am ]
Post subject:  Debugging

Think of this as advice on how to write better code. It will be an ongoing tutorial, updated as I get time.

Author:  Martin [ Thu Oct 07, 2004 12:26 am ]
Post subject: 

1. Comments
Comments are essential to programming. This is somewhat ironic, as comments do not actually effect the code in any way. A comment is just what it sounds like; it is a programmer's remark, or a note in the code.

In most languages, comments are tagged in one of two ways: there are single line comments, which are usually denoted by '//' and there are encasing comments, opened by '/*' and closed by '*/' . Instead of '//' to denote single line comments, turing uses '%'

Now, the question is: what does a comment do that is so useful that it can help me write programs that don't crash? It tells the computer to ignore a line of code. Below is an example of comments in a turing program:

code:
put "hello"
% This line is commented, and does nothing
var x : int %you can put comments onto the end of lines of code
x := 5
% Everything after the comment sign (%) is ignored by the processor.
% put "This line is actually commented out, and doesn't ever get run"
for i: 1 .. 5
  /* multiple line comments
      can be encased in comments
       like these */
     put i
     % x := x + 1
end for


Now, quick quiz: what is the value of x at the end of this program? The correct answer is 5, as the line x := x + 1 is commented out.

Alright enough of the boring stuff, now onto why comments are useful. Programmers use comments to leave themselves, or other programmers, notes in their code. This can be for two purposes: either the section of code is confusing, and writing out what it does in english helps make it easier for you to understand, or to simply make it easy to start in the middle of the code and know what is happening. It doesn't matter how good of a programmer you think you are, well commented code is essential. Now, by well commented, I don't mean excessively commented. Lines that are obvious what they do don't deserve comments. As follows:

Useless
code:
var x: int %this is an integer

Anyone could have figured this out
Good
code:
var x: int %stores the number of sheep

Much better, this comment is short, and explains exactly what the variable does.

More specific uses of comments will be explained in later tutorials.

Author:  wtd [ Thu Oct 07, 2004 2:08 am ]
Post subject: 

Even better, use:

code:
var numberOfSheep : int


No need for comments. Smile

Author:  shorthair [ Thu Oct 07, 2004 10:57 am ]
Post subject: 

would you rather type x every time , or numberofsheep


by commenting , you have to only write it once and you get hte point acroos,

wtd your way requires much more effort , the only way that i would use it would be

var X ,NumberOfSheep : int
NumberOfSheep := X

Very Happy Very Happy Very Happy

sorry had to be a little sarcastic there

Author:  Martin [ Thu Oct 07, 2004 11:08 am ]
Post subject: 

Damn it guys, that was coming next.

Author:  Martin [ Thu Oct 07, 2004 11:26 am ]
Post subject: 

2. Pre and Post Conditions
Pre and post conditions are simply a specific use of comments. The pre condition of a function is basically a statement of has to be true going into the function. The post condition of a function is what is true coming out of the function.

code:
function divide (a, b : int) : real
   result a / b
end divide


So now we have to ask ourselves when this function will go wrong. The answer is, clearly, when b = 0, the program will crash and return a divide by zero error. What happens after the function is complete? It returns a/b. So, we put these facts in pre and post conditions:

code:
function divide (a, b : int) : real
   %Pre: b is not equal to 0
   %Post: returns a divided by b
   result a / b
end divide


Now the problem with this example is that it is very obvious. Anyone who's used turing for a week could look at that and tell you what it does. The larger your function grows, the more difficult it becomes to figure out what exactly it does. Take this function, for example (in java, I didn't feel like translating it):

code:
//pre: takes an ordered list of rowIndicies and colIndicies
        //post: returns the subMatrix with rows as numbered in rowIndices, and columns as numbered by colIndices, or null should there be a problem with rowIndices
        public Matrix subMatrix(int[] rowIndices, int[] colIndices) {
                int subrows=rowIndices.length;
                int subcols=colIndices.length;

                if (rowIndices[0]<1 || rowIndices[0]>rows) {
                        System.out.println("Row index out of bounds\n");
                        return null;
                }
                for(int i=1; i<subrows; i++)
                        if (rowIndices[i]<1 || rowIndices[i]>rows || rowIndices[i]<=rowIndices[i-1]) {
                                System.out.println("Row index out of bounds or unordered\n");
                                return null;
                        }

                if (colIndices[0]<1 || colIndices[0]>cols) {
                        System.out.println("Column index out of bounds\n");
                        return null;
                }
                for(int i=1; i<subcols; i++)
                        if (colIndices[i]<1 || colIndices[i]>cols || colIndices[i]<=colIndices[i-1]) {
                                System.out.println("Column index out of bounds or unordered\n");
                                return null;
                        }
                       
                Matrix b=new Matrix(subrows,subcols);
                for (int i=1; i<=subrows; i++)
                        for (int j=1; j<=subcols; j++)
                                b.set(i,j,get(rowIndices[i-1],colIndices[j-1]));
 
                return b;
        }


As you can see, pre and post conditions become even more useful.

Next, I will explain error checking within a function

Author:  JHanson90 [ Thu Oct 07, 2004 1:42 pm ]
Post subject: 

shorthair wrote:
would you rather type x every time , or numberofsheep


by commenting , you have to only write it once and you get hte point acroos,

wtd your way requires much more effort , the only way that i would use it would be

var X ,NumberOfSheep : int
NumberOfSheep := X

Very Happy Very Happy Very Happy

sorry had to be a little sarcastic there


I would rather use the 'numberofsheep' variable. Instead of making the comment everytime you think that you will forget what 'x' was, you could just avoid the coment altogether. I use comments as a form of explaining how the program works and what I am going to do with the variable, not so much telling you what the code is doing.

Author:  Tony [ Thu Oct 07, 2004 2:11 pm ]
Post subject: 

ideally you should be able to look at a block of code and be able to explain what it does without refering to a comment you wrote elsewhere.

even though
code:

a = f(b);

is short to write, it is not descriptive at all. If there's an error in the code and somebody is trying to figure out the (supposedly corrupt logic) they must scroll up to variable declarations to find out what a/b are, and then locate function f to find out what that does. And if you keep up this style of coding, you can really send somebody on a wild goose chaise for comments using nested functions
code:

x = apples(oranges+dan)*table(pen(42-x));

any idea what the line above does? Laughing

Author:  rizzix [ Thu Oct 07, 2004 2:32 pm ]
Post subject: 

and avoid doing something useless like this:
code:

_ := __(___)
just to let u know its perfectly valid code.. but dont ask me what it does Razz

Author:  wtd [ Thu Oct 07, 2004 6:38 pm ]
Post subject: 

rizzix wrote:
and avoid doing something useless like this:
code:

_ := __(___)
just to let u know its perfectly valid code.. but dont ask me what it does Razz


How is assigning the result of a function to a variable useless?

Author:  Tony [ Thu Oct 07, 2004 7:26 pm ]
Post subject: 

i dont know about you wtd, but imo, __() is not a very descriptive function name Laughing

Author:  wtd [ Thu Oct 07, 2004 7:31 pm ]
Post subject: 

Ah. I thought he was merely referring to a basic pattern.

Author:  Martin [ Thu Oct 07, 2004 9:43 pm ]
Post subject: 

People, have a little faith in me Wink

Author:  wtd [ Sat Oct 09, 2004 12:01 am ]
Post subject: 

Functional Decomposition

Huh? What now?

Basically, that rather dry term means breaking a problem into several smaller problems, each with a meaningful name to indicate what's going on.

A function or procedure is a black box. It takes in certain pieces of data and does something. So long as it does those things correctly, we don't particularly care how it accomplishes them.

Why is this important?

By breaking a program up into several smaller problems we end up with small, simple problems that are easier to debug than if we tried to take on the whole problem all at once.

Once each smaller problem is debugged, you can then use it freely in the program without worrying that the code it contains is a source of problems.

Breaking up a program also greatly improves collaboration between two or more programmers on one project. You can, as a team, decide on what functions and procedures to use, and how they should behave, then split them up and separately implement those functions and procedures.

Lastly...

Creating functions and procedures to handle smaller problems in your program means that you give a name to commonly used code. Rather than retyping (or copying and pasting) bits of code you use frequently, you only write the code once.

Should you go back later and want to change that code, you need only do it in one place. The alternative is to change code in several places, and hope you don't miss any.

Author:  wtd [ Sat Oct 09, 2004 12:09 am ]
Post subject: 

Of course, the last point in my previous post is just generally good practice.

If you can write code once, then only write it once.

Bad

code:
if foo = 42 then
   put "Something!"
   put foo * 2
else
   put "Something!"
   put foo / 2
end if


Good

code:
put "Something!"
if foo = 42 then
   put foo * 2
else
   put foo / 2
end if

Author:  Martin [ Fri Oct 15, 2004 10:33 am ]
Post subject: 

4. Pen and paper
Okay, we're almost at the actual programming, but this stage is essential. Get out a pad of paper and your favourite writing device, and on paper, figure out what it is you want your program to do. No, this doesn't mean just write code: make a flowchart, trace through what you want your program to do, and figure out how to. Sure, you'll end up scrawling down a few lines here and there, but for the most part it's just to make your ideas tangible.

For example, my current computer science project requires me to create a sparse matrix, that is, a matrix that is composed mostly of zeros. This SparseMatrix class has to be able to store the matrix efficiently, be able to transpose the matrix, and be able to multiply the matrix by either another SparseMatrix or a DenseMatrix (one not composed mostly of zeros). We chose to do this with linked lists, and, if you've used linked lists, you know that they can get confusing very easily. Out comes the trusty pen and paper, and we figured out an algorithm, and in no time, the program worked.

Basically, if you know what you are going to do before you start coding, it's much better than if you just figure it out as you go along.


: