Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Diagnosing Java code: Assertions and temporal logic in Java programming

Introduce temporal logic to assertions to supplement testing

Eric Allen (eallen@cs.rice.edu), Ph.D. candidate, Java programming languages team, Rice University
Eric Allen has a bachelor's degree in computer science and mathematics from Cornell University and is a PhD candidate in the Java programming languages team at Rice University. Before returning to Rice to finish his degree, Eric was the lead Java software developer at Cycorp, Inc. He has also moderated the Java Beginner discussion forum at JavaWorld. His research concerns the development of semantic models and static analysis tools for the Java language, both at the source and bytecode levels. Eric is the lead developer of Rice's experimental compiler for the NextGen programming language, an extension of the Java language with added language features, and is a project manager of DrJava, an open-source Java IDE designed for beginners. Contact Eric at eallen@cs.rice.edu.

Summary:  Although traditional assertions can increase the amount of checking that can be done over Java code, there are many checks you just can't perform with them. One way to fill this gap is with "temporal logic," a formalism used to describe how a program state will change over time. In this article, Eric Allen discusses assertions, introduces temporal logic, and describes a tool for processing temporal logic assertions in your programs. (The next article examines previous bug patterns and the application of temporal logic.)

View more content in this series

Date:  01 Jul 2002
Level:  Introductory

Comments:  

We can all agree that more checking of your Java code is better than less checking, and we've examined the use of assertions in testing new and improved programming. But while traditional assertions can increase the amount of checking that can be done, there are many checks we just can't perform with them.

However, there is a way to fill the checking gap that assertions leave. That is with the use of temporal logic. Temporal logic is a formalism used to describe how a program state will change with time. Let's discuss assertions and their properties and how temporal logic fits into checking. Then we'll take a look at a tool for processing temporal logic assertions.

Assertions and their properties

In addition to type checking and unit tests, assertions provide a great way to determine that various properties are maintained in a program.

Let's take a quick look at three categories of common assertion properties (common, but which don't offer us the full coverage we'd like), compare them with the types of program properties that can be expressed in a traditional assertion language, and examine assertion properties that are necessary for a multithreading context but are impossible to express as conventional assertions. We'll also offer some code examples.

Common assertion properties

Traditionally, assertion properties fall into one of these three categories:

  • Pre-conditions assert that a property holds before execution of a code block.
  • Post-conditions assert that a property hold after execution of a code block.
  • Invariants assert that a property holds before and after the execution of a code block.

As helpful as assertions of these typical forms can be, they don't quite have the range for all the properties we'd like to be able to hold in a program. Let's look at typical assertion-expressed program properties.

Program properties expressable as assertions

This is just a short list of the types of program properties that can be expressed in a traditional assertion language -- properties that any programmer would like in code:

  • To ensure that any nonce is generated only once
  • To assert that documents are never accessed by unauthorized agents
  • To assert that each thread is given a chance to run
  • To assert that the system will never get itself into deadlock

A nonce (number used once) generator is used by security protocols to ensure freshness of transactions. As a simple concept in security, it is important to ensure that once a particular nonce is generated, it is not generated again. Another important security assertion is that secure documents are never accessed by unauthorized agents.

In multithreaded code, we'd like to assert that each thread is eventually given a chance to run. We'd also like to assure that the system will never get itself into a state where two or more threads are waiting on each other to supply a resource before they can continue processing (also known as deadlock).

Essential, non-conventional assertion properties

Following are two very useful types of properties that we'd like to make (and that we often want to make in the context of multithreaded code) that are simply not possible to express with conventional assertions:

  • Safety assertions
  • Liveness assertions

Safety assertions state that certain undesirable states of the system will never be reached under any circumstances. Liveness assertions state that certain events are guaranteed to occur eventually -- for instance, that a given thread will eventually wake up instead of sleeping forever.

Temporal logic can help make these assertions.


Where the temporal logic comes in

temporal logic

Temporal logic defined

Temporal logic is a type of modal logic that is used for reasoning about changing properties with time.

Keeping time in mind, there are two general kinds of temporal logic:

  • One that models the future as a linear sequence of events
  • One that models the future as a tree branching out with various possibilities

In this article, we will only consider the temporal logic that models the future as a linear sequence of events. (The "branching tree" logic is quite cool, but it's computationally less tractable.)

A temporal logic is normally built atop a simpler set of atomic (small-unit) propositions, such as traditional program assertions. Various modal operators can then be applied to these atomic assertions to generate more complex assertions. The chain continues since traditional, Boolean, logical operators (such as and or or) can be applied to these assertions to generate even more complex assertions. Newly generated assertions can generate still more complex assertions, ad infinitum.

Temporal logic employs three (or four, depending on the model) common modal operators.

The typical modal operators


How can I check up on my temporal logic?

These modal operators are usually available in temporal logic:

  • Always
  • Sometime
  • Until
  • Next (special case)

When applied to an assertion, Always ensures that the assertion continues to hold throughout the remainder of the execution of the program.

A much weaker operator, Sometime in a sense is a relative of Always. When applied to an assertion, Sometime stipulates that there must be some point in the future of the execution of the program during which the assertion holds.

Until works over two assertions, stipulating that as soon as the first assertion ceases to hold, the second must hold thereafter.

In contexts where time can be a model that consists of a series of discrete steps (as it can during, say, the execution of a program), you will sometimes see the Next operator added to this illustrious list. When Next is applied to an assertion, it stipulates that the assertion holds in the "next" step. Of course, this only makes sense when we are breaking time up into discrete steps.

Listing 1 shows some examples of temporal logic assertions:


Listing 1. Sample temporal logic assertions
Always x != 0
Sometime x == 0
{x == y} implies {Next {x == y + 1}}
{x == y} Until {y == 0}
{x == 0} implies {Next {Always {x != 0}}} // x is zero only once
Sometime {! this.isInterrupted()} // this thread is not interrupted forever

Here's an example assertion for two threads that asserts they never deadlock. (Note that the Boolean method isWaitingOn is used to check if one thread is holding on a task performed by the other.)


Listing 2. A sample to illustrate multithreading
Always {x.isWaitingOn(y) implies {! y.isWaitingOn(x)}}

And temporal logic can be extended.

Extending the language

We can also extend the language of temporal logic to include quantifiers over collections of values in databases. For example, we could check that the assertion always held for all values in a table or for at least one value in the table.

With this level of expressiveness, we can form extremely powerful safety and security assertions. For example, consider a context where explicit agent objects can request access to various documents. We can form assertions about the clearance of the agents that can view various documents.

The following assertion guarantees that no agent views a document until he has clearance to do so:


Listing 3. A sample to illustrate database security
ForAll agents in AgentPool
  {ForAll document in TopSecretDocumentPool
    {{! agent.canView(document)} Until {agent.hasClearanceFor(document)}}}

Now, at this point you might protest: "Well, it's great that I can say all of these things, but I don't have any way to check what I say is true, so what's the point?!"

To that I say: there are tools for checking just these types of assertions. In the case of digital circuits, assertions like these are statically verified before the chip is built.

In the case of software, our ability to statically check such assertions is paltry, but quality tools exist for checking that these assertions hold during particular runs of the program (such as, say, the runs of your unit tests). Assertions like these can help you to leverage unit testing to a much greater degree; each temporal logic assertion can correspond to countless traditional assertions (and that's just in cases where traditional assertions could be used to express the assertion at all).

Temporal Rover, from Time Rover Inc., is a tool for processing temporal logic assertions in Java programs and generating valid Java code from the assertions. (See Resources.) The company also offers a tool, DBRover, that works over database tables.

Temporal Rover includes all of the temporal operators as well as others designed for discussing events that occurred in the past. DBRover can quantify assertions over values in a database. Unfortunately, these tools are not free, but they do offer a 30-day free trial version.

Like assertions in JUnit, Temporal Rover/DBRover assertions give the programmer the option to print diagnostic messages when assertions fail. In fact, the syntax of Temporal Rover assertions is the same syntax I've used in the examples above, where assertions taken by the modal operators are surrounded with braces. These assertions are then passed to a TRAssert function (Temporal Rover Assert) with the following syntax:

/* TRAssert{<assertion> => <output string>}

The <output string> is displayed when the assertion fails to hold. In this way, TRAssert statements can be embedded into valid Java programs and these programs can still be compiled without Temporal Rover (of course, compiling without Temporal Rover will prevent the assertions from having any affect).


A timely last word

Temporal logic assertions like these can help you to leverage unit testing to a greater degree because each temporal logic assertion can correspond to many traditional assertions. This means that these assertions are so powerful that they can help in a big way to stamp out many of the classic bug patterns discussed in this column.

In the next article, I will re-examine several bug patterns in the context of temporal logic assertions and demonstrate how to use these assertions to eliminate occurrences of the pattern.


Resources

  • The Stanford Encyclopedia of Philosophy carries a broad discussion of the philosophical and mathematical foundations of temporal logic.

  • The Spin project at Bell Labs -- a widely distributed software package that supports the formal verification of distributed systems -- is an example of temporal logic model checking for hardware verification.

  • The assertion facility is one eagerly awaited new feature of the Java 1.4 release. Learn more about it in "Magic with Merlin: Working with assertions" (developerWorks, February 2002).

  • In a previous Diagnosing Java code installment, "The Fictitious Implementation bug pattern" (developerWorks, August 2001), Eric Allen shows you how to use assertions and unit tests as executable documentation.

  • Granville Miller discusses the Unified Modeling Language and sequence diagramming, examining the role of conditional logic in sequence diagramming, in "Java Modeling: A UML workbook" (developerWorks, June 2001).

  • "Testing, fun? Really?" (developerWorks, March 2001) helps you integrate testing into your daily development activities.

  • Follow along in "Automating the build and test process" (developerWorks, August 2001) as Erik Hatcher shows you how he has modified the popular Ant 1.3 and the JUnit test framework for complete, customized automation of the build and test process.

  • "Dynamic Type Checking in Jalapeno" presents a variety of techniques for performing dynamic type checking, reducing the run-time overhead of such tests.

  • Check out this XP site for a summary of the ideas behind extreme programming.

  • The JUnit Web site provides links to many interesting articles from a multitude of sources that discuss program testing methods.

  • You can check out the Temporal Rover trial at the Time-Rover Web site.

  • Read all of Eric Allen's Diagnosing Java code articles.


  • Find more Java resources on the developerWorks Java technology zone.

About the author

Eric Allen has a bachelor's degree in computer science and mathematics from Cornell University and is a PhD candidate in the Java programming languages team at Rice University. Before returning to Rice to finish his degree, Eric was the lead Java software developer at Cycorp, Inc. He has also moderated the Java Beginner discussion forum at JavaWorld. His research concerns the development of semantic models and static analysis tools for the Java language, both at the source and bytecode levels. Eric is the lead developer of Rice's experimental compiler for the NextGen programming language, an extension of the Java language with added language features, and is a project manager of DrJava, an open-source Java IDE designed for beginners. Contact Eric at eallen@cs.rice.edu.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10678
ArticleTitle=Diagnosing Java code: Assertions and temporal logic in Java programming
publish-date=07012002
author1-email=eallen@cs.rice.edu
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).