Unformatted text preview:

Assertions and Exceptions 6.170 Lecture 11 Fall 2005 10.1. Introduction In this lecture, we’ll look at Java’s exception mechanism. As always, we’ll focus more on design issues than the details of the language, which can be found in one of the recommended Java texts. We’ll discuss the general issue of making your code more robust with runtime assertions; how to use exceptions for communicating back to callers of a method, even in non-failure situations; and how to decide whether to use checked or unchecked exceptions. 10.2. Defensive Programming Suppose you are designing a compiler. Since the compiler is under constant development, and is large and complex, it is likely to contain some bugs despite your best efforts. Defensive programming is a way to mitigate the effects of bugs without knowing where they are. Adopting defensive strategies is not an admission of incompetence. Although any large program is likely to have bugs in it, even a bug-free program can benefit from defensive programming. You may have to deal with a database that may occasionally be corrupted. It would be too hard to predict every possible form of corruption, so you take a defensive strategy instead. Here’s how defensive programming works. When you’re writing some code, you figure out conditions that you expect to hold at certain points in the code; these are called invariants. Then, rather than just assuming that these conditions hold, you test for them explicitly. If a condition is false, you abort the computation. For example, suppose that in your compiler you maintain a vector of symbols, and some other vectors, each of which contains objects holding information about symbols. class Symbols {Vector symbols;Vector types;Vector positions; ... } To access the information for a given symbol, you have to access the element of the information vector with the same index. Given a symbol sym, to obtain its type for example, we take the element of the types vector in the same position: int i = symbols.indexOf (sym);Type t = types.get (i); 1This code will only work if the symbol being looked up is indeed in the symbols vector, and if the two vectors have the same length, so that the indexing in the second statement succeeds. If the second statement fails, then something has gone wrong, and it is unlikely that the compiler will be able to generate correct code. So it would be best to waste no more resources and terminate the program immediately. In fact, we can do better and notice the problem after the first statement. We do this by inserting a runtime assertion: int i = symbols.indexOf (sym); if (! (i >= 0)) System.exit (1); ... Type t = types.get (i); If the call to indexOf returns -1, indicating that the symbol is not in the vector, we terminate the entire compiler by calling the special method exit of the System class. To make runtime assertions easy to write, most programmers define a procedure, so they can write, for example: assert (i >= 0) This also demonstrates the documentation value of assertions. Even if they are not executed, they help someone reading the code immeasurably to understand what it’s doing. Two important questions arise: · Where and what kind of runtime assertions are best? · How should you abort execution? 10.3. Runtime Assertions First, runtime assertions shouldn’t be used as a crutch for bad coding. You want to make your code bug-free in the most effective way. Defensive programming doesn’t mean writing lousy code and peppering it with assertions. If you don’t already know it, you’ll find that in the long run it’s much less work to write good code from the start; bad code is often such a mess it can’t even be fixed without starting over again. When should you write runtime assertions? As you write the code, not later. When you’re writing the code you have invariants in mind anyway, and writing them down is a useful form of documentation. If you postpone it, you’re less likely to do it. Runtime assertions are not free. They can clutter the code, so they must be used judiciously. Obviously you want to write the assertions that are most likely to catch bugs. Good programmers will typically use assertions in these ways: · At the start of a procedure, to check that the state in which the procedure is invoked is as expected. This makes sense because a high proportion of errors are related to misunderstandings about interfaces between procedures. · At the end of a complicated procedure, to check that the result is plausible. This kind of assertion is sometimes called a self check. · When an operation is about to be performed that has some external effect. Runtime assertions can also slow execution down. Novices are usually much more concerned about this than they should be. Do not use runtime assertions for testing the code and turn them off in the official release. A good rule of thumb is that if you think a 2runtime assertion is necessary, you should worry about the performance cost only when you have evidence (eg, from a profiler) that the cost is really significant. Nevertheless, it makes no sense to write absurdly expensive assertions. Suppose, for example, you are given an array and an index at which an element has been placed. It would be reasonable to check that the element is there. But it would not be reasonable to check that the element is nowhere else, by searching the array from end to end: that might turn an operation that executes in constant time into one that takes linear time (in the length of the array). 10.4. Assertions in Java In Java version 1.4, runtime assertions have become a built-in feature of the language. The simplest form of the assert statement takes a boolean expression and throws AssertionError if the boolean expression evaluates to false: assert (x >= 0); The assert statement is a recent addition to the Java language, so it is still a little painful to use. First, assert is not recognized by the Java compiler at all unless you add a special switch to the compiler command line: javac –source 1.4 MyClass.java A second problem with Java assertions is that assertions are off by default. If you just run your program, none of your assertions will be checked! You have to enable assertions explicitly by passing –ea (which stands for “enable assertions”) to the Java virtual machine: java –ea MyClass A third problem is that Java assertions are not backward compatible. You can’t run a compiled


View Full Document

MIT 6 170 - Assertions and Exceptions

Download Assertions and Exceptions
Our administrator received your request to download this document. We will send you the file to your email shortly.
Loading Unlocking...
Login

Join to view Assertions and Exceptions and access 3M+ class-specific study document.

or
We will never post anything without your permission.
Don't have an account?
Sign Up

Join to view Assertions and Exceptions 2 2 and access 3M+ class-specific study document.

or

By creating an account you agree to our Privacy Policy and Terms Of Use

Already a member?