by Qusay H. Mahmoud
Classes in an OOP language should be known not only by the methods they provide, but also by the behavior and formal properties of these methods. The Eiffel programming language, for example, encourages programmers to express class behaviors by writing assertions that may appear in the following roles:
These three roles collectively support what is called the contract model of programming, a model that's well-supported by the Eiffel programming language. Java, on the other hand, doesn't have built-in support for the contract model of programming. Actually, Java doesn't even have built-in support for assertions. In this article, we'll show you how to implement assertions in Visual J++.
About assertionsAn assertion is a Boolean expression that, if evaluated as FALSE, indicates a bug in the code. This mechanism provides a way to detect when a program starts falling into an inconsistent state. Assertions also are excellent to use for documenting assumptions and invariants about a class.
Using assertions helps programmers write better code in terms of correctness, readability, and maintainability. Thus, assertions improve the odds that the behavior of a class matches the expectations of its clients.
In C/C++, you can use assertions through assert. In ANSI C, assert has the following definition:
void assert(int expression)
The assertion will be executed only when the macro NDEBUG is undefined. The program will be aborted if the expression evaluates to false (0); if the expression evaluates to true (non-0), assert has no effect.
For performance reasons, however, you should write assertions into software in a form that can be optionally compiled. Thus, assertions should be executed with the code only when you're in the debugging stage of software development—where assertions will really help in flushing out errors.
Implementing assertionsYou can implement assertions in Java quite nicely. First, create a new exceptions class for your assertions class, as shown in Listing A.
Listing A: An exceptions class
AssertionException.java
public class AssertionException extends
RuntimeException {
public AssertionException() { super(); };
public AssertionException(String msg) {
super(msg);
}
}
Listing A extends RuntimeException, a direct subclass of Exception. Basically, there are two kinds of exceptions: checked and unchecked. The possible exceptions in Java are organized in a hierarchy of classes rooted at class Throwable, which is a direct subclass of Object. The classes Exception and Error are direct subclasses of Throwable. Instances (and subclasses) of Error and RuntimeException are called unchecked exception(s) (classes).
In checked exceptions, the Java language checks at compile time whether a Java program contains handlers for exceptions. However, unchecked exceptions (as in RuntimeExceptions) are excluded from this checking. Thus Java simplifies the programmer's task by not requiring you to declare such exceptions, which could be an irritating process.
The code in Listing B implements an assert method, which takes a Boolean expression as an argument and checks whether it's true or false. If it's false, your new exception, AssertionException (declared in Listing A), will be thrown; otherwise, nothing happens. Note that in the assert method, you're also checking whether the value of NDEBUG (which is Boolean) is on or off. If NDEBUG is on (set to true), then the assertion is to be executed; otherwise it should have no effect. Also, you'll note that clients who use the Assert class should be able to change the value of NDEBUG from their own programs.
Listing B: An assert method
Assert.java
public class Assert {
public static boolean NDEBUG = true;
public static boolean assert(
boolean expression)
throws AssertionException {
if (NDEBUG && !expression) {
throw new AssertionException();
}
return true;
}
}
Listing C provides a very simple demonstration of how to use this Assert class. Note that if you don't want assertions to be executed as part of the code, then you could declare the line
Assert.NDEBUG = false;
which is really an easy way of turning off the execution of assertions.
Listing C: Implementing the assert class
TestAssertion.java
import java.io.*;
public class TestAssertion {
public static void main(String argv[]) {
BufferedReader is = new
BufferedReader(new
InputStreamReader(System.in));
System.out.print(
"Please input a number: ");
System.out.flush();
String ans=null;
try {
ans = is.readLine();
} catch(IOException e1) {
System.out.println("Error: "+e1);
}
int n = Integer.parseInt(ans);
// Assert.NDEBUG = false;
// Uncomment the above line
// to turn assertions off.
Assert.assert(n>0);
// Use n.
}
}
If you run the program in Listing C, you'll see the following output:
% java TestAssertion
Please input a number: -1
AssertionException
at Assert.assert(Assert.java:5)
at TestAssertion.main
(TestAssertion.java:15)
A word of caution: Never use the Assert class expression that involves side effects. Writing
Assert.assert(++i > 0)
for example, isn't a good idea, because i won't be incremented if Assert.NDEBUG is set to false!
ConclusionWhen writing programs, you'll find it's a good idea to put checks at strategic places for violations of basic assumptions. These checks help in debugging code. The Assert class implemented in this article provides a convenient way for programmers to abort Java programs while printing a message stating where in the program the error was detected. Remember, these messages are for us—the programmers—and not for users.
Qusay H. Mahmoud is a graduate student in computer science at the University of New Brunswick, Saint John, N.B., Canada. For his thesis, he implemented a distributed computing system over the Web using Java. You can reach him at qsay@garfield.csd.unbsj.ca.
Copyright © 1998, ZD
Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of ZD
Inc. Reproduction in whole or in part in any form or medium without
express written permission of ZD Inc. is prohibited. All other product
names and logos are trademarks or registered trademarks of their
respective owners.