Building better programs (Part 2)
Dealing with errors
We've looked at ways to make programs better, but what if, despite all those efforts, errors creep in? Dealing with errors has been part of programming since the very beginning. The term debugging means the process of removing of errors from code, where a bug is an error. It has even had a literal meaning when there were problems with insects flying into the computer and resulting in a malfunction.
Learning from mistakes
- Use error messages and test results.
- Don't give up - everyone makes mistakes.
The key is to make use of information available to you. If you're lucky, you'll get error messages. You can also obtain more information by testing your code, giving you test results as a clue to what is going on. Don't be discouraged - this is part of programming, for everyone.
Main types of errors
There are three general categories of errors.
Syntax errors
- Code does not follow the syntax rules.
- English example: "gopher halibut drunkenly"
- Results in a not-necessarily-helpful error message.
The first type results from code that the computer cannot understand because it does not follow the syntax rules of the language. In English, this would be like a sentence that does not follow the rules of how a sentence is constructed, such as putting together two nouns and then an adverb. The computer will issue an error message, which as we'll see later, may or may not immediately identify the problem.
A second type of error is an error in conveying meaning.
Semantics (logic) errors
- Syntax correct, but intended meaning not conveyed.
- English example: “elbows sing hearts”
- Found by using tests.
An English sentence might be of the form noun verb noun, but still not make a lot of sense. These errors are trickier because the computer does not make any assumptions about what meaning you intended. The best way to detect these is to test your code on inputs for which you know the correct answers and to make sure that it produces the answers you expect.
A third type of error occurs when the program is being run, such as when there is an attempt to divide by zero.
Runtime errors
Example: divide by zero
Common errors
If you come up with a list of common errors for a specific language, you are likely to find many in these categories.
Syntax errors:
- A typo in the name of a variable, constant, or function.
- Missing punctuation, unmatched brackets or parentheses, incorrect placement of white space.
- Using a reserved keyword as an identifier.
A simple typo can cause trouble since the computer might think you are creating a new variable instead of referring to an old one or vice versa. Different languages use different symbols, such as commas, semicolons, colons, brackets, or blank spaces to separate or join values. If you use the wrong type or don't match up enclosures, you will break a syntax rule. Another possible problem is breaking the rules for identifiers, such as using a reserved keyword.
Semantics errors:
- Errors in mathematical precedence rules.
- Incorrect translation of a formula into code.
- Errors in conditions leading to the wrong branch.
One example of a semantics error is not using the mathematical precedence rules correctly and hence making an incorrect calculation. Another type of problem may occur if what we think we have expressed in code is not what we have actually expressed. If we accidentally tried to compute the area of a circle by squaring the diameter, we would have a semantics error. It is possible that our code might work for some cases but not all such as in the case of branching where the branch taken is not the one that was intended.
Understanding error messages
When you see an error message, the key is to find where the error first occurred.
- Focus on finding the first error.
- The first time the computer notices the error may be after the place that the error occurred.
This may not in fact be at the spot identified by the message. Consider an example in which we accidentally assign a string instead of an integer to a variable. We now create a function to determine how much extra space there is when you fill a box with item_num items each with volume item_vol.
BIG_BOX ← "1000" # volume of big box define extra_space(box_vol, item_vol, item_num) ## Determines extra space in box of volume box_vol ## when filled with item_num items of volume item_vol ## Preconditions: ## box_vol, item_vol, item_num : integer or float ## Postcondition: ## Returns: integer or floating point number ## Determine total volume of contents content_vol ← item_vol * item_num return box_vol - content_vol print(extra_space(BIG_BOX, 20, 5))
Notice that we have specified the preconditions, namely the types required for the inputs. We have also specified the postconditions, namely the type of the value returned by the function. In the body of the function, we determine the total volume of all the contents by multiplying the volume of a single item by the number of items, and then subtract the volume of the contents from the volume of the box. What happens when we run the program? We get a syntax error on the last line of the function since we are trying to subtract the number content_vol from the string box_vol. This is not where the error was made, but rather where it was first evident. And yes, we could have avoided the error in the first place by making sure that the preconditions were met each time we used the function, which we should always do.