Radford University ITEC

ITEC120-ibarland (incl. office hrs)infolectureslabshws

lect14: interfaces

Introducing interfaces

(Monday)
Consider the following three dialogues:

  1. What do you want to pick up?
      1) A rainbow
      2) A chocolate egg
      3) Some lint
      4) A whiteboard marker
    7
    I don't know what you're talking about.
    
    What do you want to pick up?
      1) A rainbow
      2) A chocolate egg
      3) Some lint
      4) A whiteboard marker
    2
    
    The selected Treasure might be passed to a function like grab, but that's beside the point; this dialogue just asked a user to select a Treasure from a list of Treasures.
  2. What do you want to inspect closely?
      1) A rainbow
      2) Some lint
      3) A whiteboard marker
    3
    
    This is similar to the previous item, except the seleted Treasure might be passed to some function like displayDescription. But again, the task of the above dialogue's purpose was only to select a Treasure; whoever called this dialogue will decide what to do with the selected item.
  3. What do you want to enter?
      1) Davis 225
      2) Mt Everest (west face)
    0
    I don't know what you're talking about.
    
    What do you want to enter?
      1) Davis 225
      2) Mt Everest (west face)
    1
    
    This is similar to the previous, except that you are choosing a Room instead of a Treasure.
We want to write a function for this dialogue. What is the function given? What does it return?

Hmm. how to write select? One way would be to have three different functions.

But this is annoying -- we have three diffrerent functions, yet they all do virtually the same thing! They go through each item of the list, ask that item for its getName(), and use the answer to build a message to print out.

Okay, so let's make one single method, named select. Except... What to put as the return type?? What, exactly, is the input type?

  what-type-here?  select( ArrayList<what-type-here?> );

A hack: We'll return an int (an index into the ArrayList).
The proper sol'n: (you don't need to know this, but if you like): Take in a "list of [blah]", and return a "blah"! B .. ArrayList<B>

But this hack still leaves unresolved, what to use as the input type: a list of what? And even the proper solution isn't good enough; Inside the method select, whether it's a list of Treasures or Adventurers or Rooms — how will we get the name of each thing in the list? Well, it turns out, “getName()” and “getDescription” are methods available in all of our classes Treasure, Explorer, Room.

Java lets us formalize this: we can say any class which includes those methods implements the interface “Describable”.

interface Describable {
  public String getName();
  public String getDescription();
  }

/* comments omitted for conciseness.  
 * In your actual code, copy comments from java.lang.Comparable
 * documentation, in your actual code.
 * (If you like, you can add an "@see" tag to your javadoc.)
 */
An interface is similar to a class, except: We can now have a function which takes in anything Describable:
static String summarize( Describable d ) { 
  //... d.getName() ... d.getDescription() ... 
  }
Whether d is a Adventurer or Treasure or Room is besides the point — we can pass it to summarize, and its getName and getDescription methods will be called. In particular, now we've solved our other problem: now we can say we get a list of Describables, print a nice list, have the user type a number, and return an int (and index into the list).

Now that we've told Java what Describable objects can do, all that remains is telling Java that Adventurer Treasure and Room are all Describable. We do that by changing the first (non-comment) line in their class files:

/** The class Treasure represents an item in the gRUe game
 * which can be picked up and carried around from Room to Room.
 * @author Ian Barland
 */
class Treasure implements Describable {
  // All fields and methods, as before
  // ...

  /* We had better include the code for getName() and getDescription(),
   * else Java will complain that Treasure isn't implementing Describable
   * as we pledged above.
   */
  }

Interfaces: a set of behaviors (methods). Like a class, except:

(The above was covered quickly, then we spent the last 20min going over exam2.)

ITEC120-ibarland (incl. office hrs)infolectureslabshws


An example, and lists of Describables

(Tue)
Let's actually write code summarize which can take in a Treasure, Adventurer, or Room, and returns a String with a very specific form: the name, followed by the description in parentheses. This involves several steps:

Other interfaces we've seen: Cloneable, Iterator. A very handy interface: Comparable. (Look up documentation.)

Note that class String implements Comparable. Indeed, try the following in BlueJ's code pad:

"hello".compareTo("aloha")
"hello".compareTo("sayonara")
"hello".compareTo("hello")
"hello".compareTo("Hello")
"a".compareTo("Z")
This is

Exercise: make Dogs comparable, by age ... with ties solved alphabetically.

Solution: We see that the documentation for interface Comparable tells us we only need to implement one additional method, to meet the interface. Thus:

class Dog implements java.lang.Comparable<Dog> {
  //...fields,
  //...constructors,
  //...other methods

  /**
   * @param otherDog The dog to compare the
   * @return a positive number if this Dog is greater than otherDog,
   *    zero if they compare equally, and negative if this is less
   *    than otherDog.
   *    NOTE: this class's ordering (which we are defining here with compareTo)
   *        is not consistent with equals!  You might have Dogs d1,d2 such 
   *        that !(d1.equals(d2)), and yet (d1.compareTo(d2) == 0).
   *        This is asking for trouble.
   *        (See lab14 for a remedy.)
   * @see compareTo, in java.lang.Comparable.
   */
  public int compareTo( Dog otherDog ) {
    if (this.getAge() > otherDog.getAge()) {
      return +1;
      }
    else if (this.getAge() < otherDog.getAge()) {
      return -1;
      }
    else if (this.getAge() == otherDog.getAge()) {
      return 0;
      }
    else {
      System.err.println( "uh-oh: Dog.compareTo fell through all cases!" );
      return 0;  // Yikes, not a safe answer.
      }
    }

  }
Challenge: Can you be sneaky, and write this method in a single line? Hint: make use of the fact that compareTo is specified to return positive,zero,negative and not just +1,0,-1. What is an expression which is positive when this is older than otherDog, zero when they're the same age, and negative when this is younger?

ITEC120-ibarland (incl. office hrs)infolectureslabshws


Interfaces: multiple impementations; achieving polymorphism

In yesterday's lab, we saw that Java has a built-in method sort( List<T> data); this will sort your list of Treasures, according to whatever your specific idea of what makes a Treasure “big”. All this, even though the sorting code was written before you ever conceived of class Treasure. This is a perfect example of great software re-use.

How was Java able to do this? sort

We have the same thing happening in gRUe, with Describable: you've written a function select which takes a list of Describables; in a week from now, you might make a whole new class you haven't yet dreamed of. Yet if you make that class implement Describable, then the already-written function select will work without modification. Neat!

When a function (or variable) can process (or hold) multiple types of inputs (e.g. Explorer vs. Room vs. Treasure) even when it doesn't know the exact “run-time” type of its input, we say it's polymorphic. One example is

static String summarize( Describable d ) { 
  return d.getName() + ": " + d.getDescription();
  }
Another example is java.util.Collections.sort, which we called in lab on lists-of-Treasure we just created.

Observe that a Treasure can do everything a Describable can do (and more). Every Treasure is a Describable.

Aside: Programming-language designers have an odd way of looking at types: as sets. That is, boolean is the set {true,false} and int = { 0, 1, -1, 2, -2, … 2147483647, -2147483647, -2147483648 } (large, but finite). Similarly, String = { "", "a", "b", …, "aa", "ab", … }. (This one is an infinite set.) Even, Treasure is the set of all conceivable Treasure values.
What does this have to do with polymorphism? In this view, what's the relation between type Treasure and type Describable? Subset! That is, TreasureDescribable.

One glitch: parameterized types with polymorphism: While a Treasure can do anything a Describable can do, how about this:

Can a ArrayList<Treasure> do anything that an ArrayList<Describable> can do?
At first blush, you'd think so. However, there's a glitch: an ArrayList<Describable> can add a Room, but an ArrayList<Treasure> certainly can't!

The solution: when working with parameterized collections of a polymorphic type, declare the argument not to a full-fledged collection of that type, but rather “a collection of something which extends that type”. That is: not sort( List<T> data ), but sort( List<? extends T> data ). Or for our homework: select( ArrayList<? extends Describable> data ). 2

Hey! why does sort take a “List”; the name of the type is “ArrayList”. What gives?
Can you guess? Yes! ArrayList implements the interface List! (What do you think class ArrayList uses internally, to achieve the appearance of a List?) In fact, this is a common use of interfaces: to allow for multiple implementations.

In our hw07 assignment: you'll have a general interface IO, and then a specific class TextIO extends IO. But, I could also write another, separate implementation: class GuiIO extends IO. In your code:

IO myIO = new TextIO();
//...
myIO.display( "hello" );
myIO.select( … );
Note that the declared type and actual type of myIO are different! That's okay. Notice that if we have other implementations, we can just substitute:
IO myIO = new GuiIO();
//...
myIO.display( "hello" );
myIO.select( … );

Interfaces define behavior. The comments explaining what the methods are expected to do are critical. If some class NotIO has the methods select and display, but they do conceptually different tasks, then NotIO shouldn't implement IO!

For instance, if you have a class with a method named compareTo, which returns a positive/zero/negative int number as required, but it also changes the object so that it becomes as big as the object just compared against, then certainly that class shouldn't implement Comparable.


1Okay, if you don't explicitly declare an interface method to be public, then Java will do that for you. So I encourage you to include the public declaration, just to keep things clear.      back

2 You won't need to know any of this this on an exam; it's just an explanation of why it's needed on the homework. It's a subtle point. In programming-languages jargon: “while most types are covariant, collections can be contravariant”, where “A extends B” doesn't imply “collection<A> extends collection<B>”)      back

ITEC120-ibarland (incl. office hrs)infolectureslabshws


©2006, Ian Barland, Radford University
Last modified 2006.Dec.02 (Sat)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Powered by PLT Scheme