SE450: Lecture 6 (DBC/Quiz I)

Contents [0/24]

Overview of Today's Class [1/24]
Type Safe Enum [2/24]
DBC: Design By Contract [3/24]
Assertions: The assert functionality in Java 1.4 [4/24]
Assertions: Enabling and Disabling assertions [5/24]
Assertions: Assertions Example [6/24]
Assertions: Assertions in JDK 1.3 [7/24]
DBC: Common assertion usage [8/24]
DBC: Pre/Post/Invariants [9/24]
DBC: A DBC methodology [10/24]
DBC: Java implementation conclusion [11/24]
DBC: Alternatives/APIs [12/24]
Examples [13/24]
Final Project: Requirements [14/24]
Final Project: Deliverables [15/24]
Final Project: Grading [16/24]
Final Project: Examples [17/24]
Project: Example: A Game [18/24]
Project: Example: Simulation [19/24]
Project: Example: Simple Framework [20/24]
Project: Good Projects [21/24]
Project: Bad Projects [22/24]
Homework [23/24]
Final Project proposal [24/24]

Overview of Today's Class [1/24]

Type safe enum idiom

Assertions

Design by Contract

Quiz (Last hour)

Type Safe Enum [2/24]

An enumerated type is used to hold a fixed set of constants, and name them in a fashion to make your code more readable and maintainable.

Java doesn't have an enum type like C - thankfully! They were just integer constants, and were not typesafe.

Programmers usually get around this by creating a number of public final static int variables in an interface or class and using them to enumerate types. This can be problematic. For example, you could make a Card enum for a card game

        public class Card {
            public static final int CLUBS = 0;
            public static final int DIAMONDS = 1;
            public static final int HEARTS = 2;
            public static final int SPADES = 3;
        }
    

Problems:

To do this, use a typesafe enum pattern (example from Bloch's Effective Java), go here for some from the book.

        public class Suit {
            private final String name;
            // can't be created elsewhere!
            private Suit(String name) { this.name = name; }
            public String toString() { return name; }
            
            public static final Suit CLUBS = new Suit("clubs");
            public static final Suit DIAMONDS = new Suit("diamonds");
            public static final Suit SPADES = new Suit("spades");
            public static final Suit HEARTS = new Suit("hearts");
        }
            
    

You can also provide ordering using an ordinal to assign ordering to the objects as they are created as well.

Since the enum is a full blown class, it can do anything a class can, and be much more effective than the old enumerated type - see the book and Bloch's Effective Java for more examples.

DBC: Design By Contract [3/24]

Definition: the interfaces of classes are viewed as contracts that specify benefits and obligations of both the client and the supplier (the class itself). (Bertrand Meyer)

Precondition - must be true to make the call. Indicates the bug is in the caller.

Postcondition - must be true after the call. Indicates the bug is in the provider (or in the precondition assertion!)

Invariant - must always be true (after a successful instantiation of the class, or even true for static methods if there is no object of the class created). It will be true before and after each method invocation. Indicates the bug could be in either the caller or the provider.

You can define these conditions as constraints in the UML. Just put the text describing the constraint in { }. There is also a more formal Object Constraint Language available to define constraints.

The programming language Eiffel has DBC built in. Two classes interact via a contract. A breach of contract is a bug. Eiffel provides the ability for all assertions to be propogated to subclasses, and assertions in interfaces apply to implementing classes. Read this article for some more information on DBC in Eiffel.

Assertions: The assert functionality in Java 1.4 [4/24]

Definition of an assertion: A statement containing a boolean expression that the programmer believes to be true at the time the statement is executed.

What does assert do?

What do you use an assertion for?

Syntax
AssertStatement:
assert Expression1;
assert Expression1 : Expression2 ;
Expression2 is like passing a String expression to System.out.println();

Examples:


assert i == 0;

assert b.getName() != null;

assert false;  // will always throw an AssertionError if assertions are enabled

assert i == 0 : "i != 0, loop failed"; // will pass message out in error

Did you know assertions were supposed to be part of java 1.0? They were left out because of the difficulty in creating them. Too bad they didn't make it a keyword anyway...

Assertions: Enabling and Disabling assertions [5/24]

To enable your source to contain assertions, compile your source as follows:

javac -source 1.4 MyClass.java

To enable assertions at runtime, you can do the following:

     java [ -enableassertions | -ea  ] [:<package name>"..." | :<class name> ]

The ... is used to enable assertions in the package. A single argument of ... enables assertions for the default package.

To disable asserations at runtime, you can do the following:

     java [ -disableassertions | -da ] [:<package name>"..." | :<class name> ]

Where the ... is used the same as above.

The -ea and -da flags can be used in combination to fine tune the classes that have assertions enabled.

To enable or disable assertions in the systems classes, use

java [ -enablesystemassertions | -esa ]
and
java [ -disablesystemassertions | -dsa ]

You can enable assertions in individual systems classes with the -ea and -da flags above, but with the no-arg form, system classes are not enabled by default.

Assertions: Assertions Example [6/24]

For the following code


public class MyClass {

    public static void main(String args[]) {
	assert false;
    }
}

Here is how it can be run using JDK 1.4

C:\temp>javac MyClass.java
MyClass.java:4: warning: as of release 1.4, assert is a keyword, and may not be used as an identifier
        assert false;
        ^
MyClass.java:4: not a statement
        assert false;
        ^
MyClass.java:4: ';' expected
        assert false;
               ^
2 errors
1 warning

C:\temp>javac -source 1.4 MyClass.java

C:\temp>java -classpath . MyClass

C:\temp>java -ea -classpath . MyClass
Exception in thread "main" java.lang.AssertionError
        at MyClass.main(MyClass.java:4)

C:\temp>

Note that this only works on JDK 1.4. If you are using JDK 1.3 (or you don't run your code with the -source 1.4 flag in 1.4, there is no way for you to implement the java assert feature using the native JDK tools. You have to use an assertion class. The assert cannot be left in the code.

Assertions: Assertions in JDK 1.3 [7/24]

So if you are stuck using JDK 1.3, what do you do?

You can use the Assert class provided by JUnit. This class has a number of static methods that you have already used. To use it, you just need to include junit.jar in your classpath and import the class in the file you want to use it in.


import junit.framework.Assert;

public class MyClass2 {


    public static void main(String args[]) {
	Assert.assertTrue( false );
    }
}

Here's what it will look like when you run it.

C:\temp>d:\jdk1.3.1_02\bin\javac -classpath .;d:\junit3.7\junit.jar MyClass2.java

C:\temp>d:\jdk1.3.1_02\bin\java -classpath .;d:\junit3.7\junit.jar MyClass2
Exception in thread "main" junit.framework.AssertionFailedError
        at junit.framework.Assert.fail(Assert.java:51)
        at junit.framework.Assert.assertTrue(Assert.java:38)
        at junit.framework.Assert.assertTrue(Assert.java:45)
        at MyClass2.main(MyClass2.java:7) 

With this option, there are no flags to turn assertions on or off. They are always enabled.

DBC: Common assertion usage [8/24]

Internal Invariants
replace


if(i == 0) {
 ...
} else if(i == 1) {
 ...
} else { // i == 2
 ...
}

with


if(i == 0) {
 ...
} else if(i == 1) {
 ...
} else { 
 assert i == 2;
 ...
}

Control Flow Invariants
replace


switch(value) {
 case command2.A:
  ...
  break;
 case Foo.B:
  ...
  break;
}
with

switch(value) {
 case Foo.A:
  ...
  break;
 case Foo.B:
  ...
  break;
 default:
  assert false;
}

Place assert false; in code you think will not be reached. You'll find out if it is!

Never allow assertion code to have side affects, since assertions can be disabled. Example:


  assert i++ == 3;

DBC: Pre/Post/Invariants [9/24]

Assertions can be used to implement a design by contract style of programming. In Eiffel, this is done as part of the programming language itself. How do we do this in Java? What do we have at our disposal?

Preconditions

Postconditions

Invariants

Java offers us the following:

Preconditions - usually use exceptions, especially for public APIs. If your class is used by other classes (any arbitrary class), it should throw an exception if an argument is called that violates the contract).
However, if you are using exceptions (especially checked exceptions) in private code, this can be cumbersome. You may not want to have to put try-catch blocks in all of your private code (trusted). You may prefer to use assertions at this point, since the only code using your classes should be your own.

What can happen if you use assertions in a public API?


void command(Object o) {
    assert o != null;

    String s = o.toString();
}

Postconditions - use assert. You probably don't want to throw an exception after the completion of the code. You would prefer to do a check on some value, and assert that the assumption is true. If the contract is violated at this point, there is not much that can be done. By throwing exceptions, you are asking the client to attempt to recover from it.

Invariants - use assert. This is often part of the pre and post condition code, since it must be true at both times. Write an invariant method that can be called whenever a method is called and returns. This will ensure the class meets the invariant. The method should return a boolean.

Assertions a big part of iterative developement. They are similar to writing a unit test that will guarantee that if code changes to violate a contract, it will be caught. The difference is it is run every time the method is executed, allowing a more diverse set of test cases.

DBC: A DBC methodology [10/24]

Some definitions:

query - basic and derived

command

Six Principles:

  1. Separate queries from commands
  2. Separate basic queries from derived queries
  3. For each derived query, write a postcondition that specifies what result will be returned in terms of one or more basic queries
  4. For each command, write a postcondition that specifies the value of every basic query
  5. For every query and command, decide on a suitable precondition
  6. Write invariants to define unchanging properties of objects

Some javadoc additions (supported by tools, but useful without them)

DBC: Java implementation conclusion [11/24]

What are some of the issues with a handmade DBC solution using assertions and Exceptions?

What do we get out of DBC with java?

  • Assertions can be disabled
  • Pre/Post/Invariants are not automatically inherited.
  • Interfaces can't have DBC b/c of above and because they can't provide an implementation.
  • We can still write the code for each implementation, so we can get the features manually.
  • We can use it in development while we control the assertion status.
  • We can still benefit from defensive programming techniques (i.e. we can make the system robust anyway, but the DBC techniques can deal with the accuracy that we need)

DBC: Alternatives/APIs [12/24]

If you want to do DBC for real, one of the best tools out there is iContract. I have supplied an iContract target to the build.xml file that is downloadable from the web. By using iContract, you can automatically add DBC to your code.

Some other implementations of DBC in Java are

In light of all the other tools and system problems so far, it isn't required that you use iContract. However, for those of you who have extra time, I recommend you take a look at it and try it out.

Examples [13/24]

Some examples:

/**
 * @invariant y >= 0
 */
public class Test {
    
    private int y;

    public static void main(String args[]) {
	Test t = new Test();
	t.run();
    }

    /**
     * a simple non static test function
     */
    void run() {
	try {
	    for(int i = 2; i > -9; i-=3) {
		this.command2(i);
	    }
	} catch (Error e) {
	    // don't want to do a try/catch, just here so we
	    // can show it works!
	    e.printStackTrace();
	}

	try {
	    this.command("hey");
	    this.command(null); // throws an IllegalArumentException
	} catch(Exception e) {
	    // don't need to catch this, it's a RuntimeException!
	    e.printStackTrace();
	}
    }

    /**
     * a command
     * @pre arg != null
     * @param arg a String arument
     */
    public void command(String arg) {
	if(arg == null) {
	    throw new IllegalArgumentException("arg can't be null");
	}
	System.out.println("arg set to " + arg);
	// a little extra (y didn't change, but run it anyway)
	assert(invariant() == true);
    }

    /**
     * another command
     * @post arg = arg@pre + 1
     * @param arg an int to increment
     */
    public void command2(int i) {
	int i_old = i;
	i++;
	y += i; // so we can test invariant
	System.out.println("i is " + i + ", y is " + y);
	// post condition
	assert(i == i_old + 1);
	// invariant
	assert(invariant() == true);
    }

    /**
     * an example of an invariant method
     * @return whether the class invariant has been violated
     */
    boolean invariant() {
	if(y < 0) {
	    return false;
	}
	return true;
    }

}

When run from the command line, the above prints

D:\>java -ea -classpath . Test
i is 3, y is 3
i is 0, y is 3
i is -3, y is 0
i is -6, y is -6
java.lang.AssertionError
        at Test.command2(Test.java:61)
        at Test.run(Test.java:19)
        at Test.main(Test.java:10)
arg set to hey
Exception in thread "main" java.lang.AssertionError
        at Test.command(Test.java:47)
        at Test.run(Test.java:28)
        at Test.main(Test.java:10)

Note that the AssertionError won't show up unless assertions are enabled. (java -ea)

/**
 * @invariant size() >= 0
 */
public interface Queue {
    // commands
    /**
     * @post size() == size()@pre + 1
     * @post elements().get( size() -1) == o
     */
    public void add( Object o );

    /**
     * @pre size() >= 1
     * @post size() == size()@pre - 1
     * @post forall int i in 0 .. size() -1 |
     *    elements().get(i) == 
     *       elements()@pre.get(i + 1)
     * 
     */
    public Object remove();
 
    /**
     * @post return == elements().size()
     */
    public int size();

    /**
     * @pre size() >= 1
     * @post @result == elements().get(0)
     */
    public Object head();

    /**
     * Check if queue is empty - derived query
     * 
     * @post @result == (size() == 0)
     */     
    public boolean isEmpty();

    public Vector elements();
}

Final Project: Requirements [14/24]

Goal: To apply the Object Oriented concepts and patterns that you have learned in this class in a moderately sized project.

Details

Requirements

Final Project: Deliverables [15/24]

Documentation Deliverable Details

Final presentation format:

You will register for a 15-20 minute session with me in the lab. You will demo your project and I will ask you a number of questions about it. Some of these questions will be given to you ahead of time. Some of them will not.

It is imperative that you understand your own code. I will be quizzing you on what it does and how you wrote it, so make sure you write it yourself! According to the academic dishonesty policy, you can be expelled or given an F for submitting work that is not your own.

That said, if your project will be based on or use existing code (either from work or another class), I will need a copy of the source code used before you start the project. I will assume that all other code submitted is completely written by you and that you understand it completely.

Final Project: Grading [16/24]

The grade will be assessed as follows:

Final Presentation (30%)

Report (30%)

Project (40%)

Final Project: Examples [17/24]

Examples:

Project: Example: A Game [18/24]

Any n-player game. Players interact in turns (not at the same time).

Day one: tic-tac-toe or similar; computer-versus-computer (stupid); text-based user interface (TUI).

Week one: computer or human (abstract player class).

Week two: TUI or GUI (abstract UI class(es?)).

Week three: changeable rules (abstract referee class).

Week four: specialize game. polish.

Project: Example: Simulation [19/24]

Day one: Simulate a single airport with random flights.

Week one: Model flights, simple weather problems, late flights. Saving state to a file.

Week two: TUI or GUI (abstract UI class(es?)).

Week three: Changeable weather? User controlled flights? Air traffic controlling? Redirected flights?

Week four: polish.

Project: Example: Simple Framework [20/24]

Note: This is challenging one!

Day one: Implement the most basic part of the framework (the command pattern, for example) with a simple user of the framework.

Week one: Fill out the details of the framework

Week two: Implement all the framework features

Week three: Write a program (simple) using your framework that is a little more advanced than the unit tests.

Week four: polish.

The problem here is that as the framework changes, your client code changes.

There will probably be less code in a framework, but it will have to be designed better than a simple app to work right. You will need to write a sample client app to show it works.

Project: Good Projects [21/24]

The key is designing for variation.

Variation encourages you to use a nice modular design. Force yourself to allow other options, for example, other rules, other UI's, other players, other input systems, other data storage techniques ...

Do not fix anything you don't have to.

Split logically separate functions into packages.

Design clear interfaces for your packages.

Project: Bad Projects [22/24]

Do not choose a project because you want to learn one of Java's many APIs. You will spend all your time with the API and none with your project. (This happened to me!)

Do not spend your time entering lots of data. If you do a record store, your grade will not vary by how many records there are. Lines of code that add data will of course count in the total number of lines of code, but that will only be a very small part of the grade.

Do not emphasize the GUI, or other cool things, like sound. Keep it basic. Make the code pretty. This includes things like good javadocs, good formatting, good variable names, good comments. Be very careful with Swing/AWT so that you don't embed all of your code in your interface.

Problematic:

Do not get too caught up on beautiful graphics/algorithms. Worry more about beautiful structure.

Homework [23/24]

Read Jia chapter 7, 9, and 10.1-10.2


Goal: to become familiar with the Java assertion facility and the design by contract concepts.

Your job is to implement DBC on new code you will write using Java assertions.

Add a new class to your previous homework assignments. This time you will implement a class called Airport. An Airport will consist of Runways (basically queues), and Gates.

The Airport class should have methods to set/get the Name (the code), the number of runways, add and remove Flights. You should also be able to get the Flights as a List. An airport should never be allowed to add a Flight that is already going to that Airport, or remove a flight that isn't currently at that airport, or have more flights than gates. It also should not allow null parameters in any of its functions. Your job is to write good pre and post conditions, and an invariant to ensure that these conditions hold true. Assume a very simple airport, where each flight goes to one gate, no gates are shared, and all flights happen in the same day.

Follow the six steps of the DBC methodology.

Your job is to implement an invariant method, preconditions for each command, and postconditions for each derived query. Use the java assertion facility for assertions, use an IllegalArgumentException (or a similar RuntimeException) for exceptions. Put the javadoc extensions (@invariant, @pre, and @post) in the right places with the right java code to show the condition.

Write a JUnit test called AirportTest that shows that the contracts of the methods can't be violated. You can do this by putting each call around a try block that catches an Exception that you expect to be thrown. If it fails, then catch the exception for a successful test. If it doesn't fail, then fail the test. See last week's notes for an example.

Submit a ZIP file that contains all java files and grader.txt. The files should be in the same package as you have used for your previous homework assignments, except the package for this assignment will be hw5 (i.e. se450.student.hw5).

You can use the grader.txt file from the previous homework.

Due Monday, February 17th at 5:30 PM.

Final Project proposal [24/24]

Write a one or two page description of your idea for a final project.

You should include:

(Note any special expertise that would make the project simpler for you, on other words, how your past experience in the area you plan cover will make your project better)

Place the description in a file project.txt and submit it as Project Proposal by February 20th.

Please make sure your file is in plain text, not word, rtf or other formats. Use a text editor, or if you use word and save as text, open it in a text editor before you submit it so you know it is formatted correctly.

Don't wait to start coding/designing/experimenting until next week. Get moving. I will contact you via email if I see a problem with the proposal.


Revised: 2003/2/8