next up previous
Next: 1.6.2.2 Maintaining Sample Test Up: 1.6.2 An Extended Example: Previous: 1.6.2 An Extended Example:

1.6.2.1 Type Predicates and Type Casts in Java

Most programming languages do not have an analog of Scheme predicates like empty? because they do not have a universal type that contains all other types. Java is almost identical to Scheme in this regard. All object types are subtypes of the universal type Object. If we ignore the eight primitive types (which all have corresponding wrapper types in the Object type hierarchy), then the data models of Scheme and Java are essentially identical.

To test membership in any object type T, Java provides the of postfix operator

instanceof T
For example, the expression
x instanceof String
tests whether the variable x is a String. It is equivalent to the Scheme expression
(string? x)
Hence, given the preceding program defining type IntList, Java interprets the program expressions below as follows:
new Empty() instanceof Empty      $\Rightarrow$     true
((IntList) new Cons(0, new Empty()) instanceof Empty     
$\Rightarrow$     false
"A" instanceof Empty     
$\Rightarrow$     false
The instanceof operator has the same precedence as the relational operators. (Although the second ``argument'' to instanceof must be a type name, the Java parser initially recognizes this argument as an expression.)


Finger exercise: Load the preceding program defining the IntList type into the DrJava Definitions window. Add definitions for isEmpty and isCons. In the Interactions window try evaluating the following sequence of interactive computations:

IntList empty = new Empty();
empty
IntList oneElt = new Cons(1, empty);
oneElt
empty.isEmpty()
empty.isCons()
oneElt.getFirst()
oneElt.isEmpty()
oneElt.isCons()
IntList twoElts = new Cons(0, oneElt);
twoElts.getFirst()
twoElts.getRest()
twoElts.getRest().isCons()
empty.getFirst()
empty.getRest()
"A".isEmpty()
"A".isCons()
Perform the equivalent sequence of membership tests as in the previous exercise using instanceof operators instead of the operations isEmpty and isCons.


To accommodate static type checking, Java includes a second form of type predicate not present in Scheme called a cast. You may recall that Java includes operations for casting one primitive type to another. These primitive type casts convert values of one type to ``corresponding'' values of another type. The casting operations for object types have a completely different meaning; casting a value v to an object type T performs an instanceof check on v! If the check returns false, then Java throws a NoSuchElementException indicating that the cast failed. If this exception is not caught (using the catch construct which is not discussed in this monograph), Java aborts execution and prints an error message indicating which cast failed. In contrast, primitive type casts never fail!

If object type casts can only cause a program to abort execution, what good are they? Since the cast prevents execution from continuing if the instanceof test fails, the compiler knows that the result of object casting expression

( T) e
has type T. Consequently, the static type checker in the compiler assigns the static type T to this casting expression. By inserting object casting operations in a program, you can tell the static type checker that a particular expression has a narrower (more precise) type that the type that would otherwise be assigned by the static type checking rules.


Finger exercise: Load the preceding definition of the IntList class and subclasses the DrJava Definitions window. Save your code in the file IntList.java. In the Interactions window try evaluating the following sequence of interactive computations:

IntList empty = new Empty();
IntList oneElt = new Cons(2, empty);
oneElt
oneElt.first
((Cons) oneElt).first
oneElt.rest
((Cons) oneElt).rest


next up previous
Next: 1.6.2.2 Maintaining Sample Test Up: 1.6.2 An Extended Example: Previous: 1.6.2 An Extended Example:
Corky Cartwright
2001-08-02