/* Csu213, Monday 3/12/07 We continue the stuff from last time... long ago... before spring break. You should remember the ISame interface from the last few lectures and the TestHarness Library. We define ISame again here so these notes will be self contained, but we'll write our own 'visual' tests... */ // This interface is implemented if a class is to be comparable to // any other objects. interface ISame{ boolean same(Object that); } // Represents a Book/Publication class Book implements ISame{ String author; String title; int year; // Create a Book using all information public Book(String auth, String title, int year){ this.author = auth; this.title = title; this.year = year; } // Needed for the ISame interface public boolean same(Object that){ if(!(that instanceof Book))return false; else return (author.equals(((Book)that).author) && title.equals(((Book)that).title) && year == ((Book)that).year); } // To make output look reasonable public String toString(){ return "Book( \""+author+"\", \""+title+"\", "+year+" )"; } } // Some Uses/Examples/Tests of our new Methods/Classes class BookExamples{ Book book1 = new Book("Jim", "The Oldest Book", 1932); Book book2 = new Book("John", "Mid 20th Century", 1947); Book book3 = new Book("Julie", "Very Late 20th Century", 1998); Book book4 = new Book("Jen", "The Newest book", 2007); } /* We'll use this Book class to review our earlier general 'predicate' definitions for choosing things from a List-of Books. We use ISame so we can create a List-of anything which is still comparable */ // Interface helps us create classes which will choose which Objects we // like. These will be used to filter our lists interface ISelect{ // Is the given Object of interest? boolean select(Object that); } // Represents a List of ISame abstract class ALoIS implements ISame{ // Is *this* List the same as *that* Object? public abstract boolean same(Object that); // Simple add() method to help us build lists without typing so much public ALoIS add(ISame that){ return new ConsLoIS(that, this); } // Various Selection Functions... // Does the given selector like *any* of the ISames in this list? public abstract boolean anySuch(ISelect pick); // Does the given selector like *all* of the ISames in this list? public abstract boolean allSuch(ISelect pick); // Return a list of the ISames this selector likes from this list public abstract ALoIS collectAll(ISelect pick); } // Represents an Empty list of ISame class MtLoIS extends ALoIS{ // Nothing to construct public MtLoIS(){} // Any two empty lists are the same public boolean same(Object that){ return (that instanceof MtLoIS); } // Does the given selector like *any* of the ISames in this empty list? public boolean anySuch(ISelect pick){ return false; } // Does the given selector like *all* of the ISames in this empty list? public boolean allSuch(ISelect pick){ return true; } // Return a list of the ISames this selector likes from this empty list public ALoIS collectAll(ISelect pick){ return this; } } // Represents a non-empty list of ISame class ConsLoIS extends ALoIS{ ISame first; ALoIS rest; // Simple Constructor public ConsLoIS(ISame first, ALoIS rest){ this.first = first; this.rest = rest; } // Is this ConsLoIS the same as the given Object public boolean same(Object that){ if(!(that instanceof ConsLoIS)) return false; else return (this.first.same(((ConsLoIS)that).first) && this.rest.same(((ConsLoIS)that).rest)); } // Does the given selector like *any* of the ISames in this non-empty list? public boolean anySuch(ISelect pick){ return (pick.select(this.first) || this.rest.anySuch(pick)); } // Does the given selector like *all* of the ISames in this non-empty list? public boolean allSuch(ISelect pick){ return (pick.select(this.first) && this.rest.allSuch(pick)); } // Return a list of the ISames this selector likes from this non-empty list public ALoIS collectAll(ISelect pick){ return collectHelp(pick.select(this.first), this.first, this.rest.collectAll(pick)); } // public ALoIS collectHelp(boolean include, ISame that, ALoIS others){ if(include) return new ConsLoIS(that, others); else return others; } } // Some lists for tests below class ListExamples{ ALoIS mt, oneOld, oneNew, three, four; ListExamples(BookExamples books){ mt = new MtLoIS(); oneOld = mt.add(books.book2); oneNew = mt.add(books.book3); three = mt.add(books.book2).add(books.book1).add(books.book4); four = three.add(books.book3); } } // An ISelect for 'Old' Books class OldBook implements ISelect{ // Remember here that the default constructor is created with // no arguments public boolean select(Object b){ return ((Book)b).year < 1950; } } // Here's a few other simple ISelects to test our methods... class ChooseAll implements ISelect{ public boolean select(Object that){ return true; } } class ChooseNone implements ISelect{ public boolean select(Object that){ return false; } } public class notes_3_12_07{ public static void print(String s){ System.out.println(s); } public static void main(String[] args) { BookExamples books = new BookExamples(); ListExamples lists = new ListExamples(books); Book book4cp = new Book(books.book4.author, books.book4.title, books.book4.year); print(" *************\n Same Book Tests:"); print(" book1.same(book1): true =? "+books.book1.same(books.book1)); print(" book2.same(book3): false =? "+books.book2.same(books.book3)); print(" book1.same(new Book()): true =? "+books.book4.same(book4cp)); print(" (new Book()).same(book4): true =? "+book4cp.same(books.book4)); print("\n\n *************\n Same List Tests:"); print(" mt.same(mt): true =? "+lists.mt.same(lists.mt)); print(" oneOld.same(mt): false =? "+lists.oneOld.same(lists.mt)); print(" newList.same(three): true =? "+ (lists.mt.add(books.book2).add(books.book1).add(books.book4).same(lists.three))); print(" three.same(four): false =? "+lists.three.same(lists.four)); ISelect all = new ChooseAll(); ISelect none = new ChooseNone();; print("\n\n *************\n Simple Selector Tests:"); print(" mt.anySuch(ChooseAll): false =? "+lists.mt.anySuch(all)); print(" mt.allSuch(ChooseNone): true =? "+lists.mt.allSuch(none)); print(" three.allSuch(ChooseAll): true =? "+lists.three.allSuch(all)); print(" three.anySuch(ChooseAll): true =? "+lists.three.anySuch(all)); print(" three.allSuch(ChooseNone): false =? "+lists.three.allSuch(none)); print(" three.anySuch(ChooseNone): false =? "+lists.three.anySuch(none)); ISelect oldBook = new OldBook();; print("\n\n *************\n Old Book Tests :"); print(" mt.anySuch(OldBook): false =? "+lists.mt.anySuch(oldBook)); print(" mt.allSuch(OldBook): true =? "+lists.mt.allSuch(oldBook)); print(" three.allSuch(OldBook): false =? "+lists.three.allSuch(oldBook)); print(" three.anySuch(OldBook): true =? "+lists.three.anySuch(oldBook)); print(" oneNew.allSuch(OldBook): false =? "+lists.oneNew.allSuch(oldBook)); print(" oneNew.anySuch(OldBook): false =? "+lists.oneNew.anySuch(oldBook)); print(" oneOld.allSuch(OldBook): true =? "+lists.oneOld.allSuch(oldBook)); print(" oneOld.anySuch(OldBook): true =? "+lists.oneOld.anySuch(oldBook)); // ********************* Generic Simple 'same' tests ********************** BookGExamples booksG = new BookGExamples(); ListGExamples listsG = new ListGExamples(booksG); BookG book4cpG = new BookG(booksG.book4.author, booksG.book4.title, booksG.book4.year); print("\n\n *************\n Generic Same BookG Tests:"); print(" book1.same(book1): true =? "+booksG.book1.same(booksG.book1)); print(" book2.same(book3): false =? "+booksG.book2.same(booksG.book3)); print(" book1.same(new Book()): true =? "+booksG.book4.same(book4cpG)); print(" (new Book()).same(book4): true =? "+book4cpG.same(booksG.book4)); print("\n\n *************\n Generic Same ListG Tests:"); print(" mt.same(mt): true =? "+listsG.mt.same(listsG.mt)); print(" oneOld.same(mt): false =? "+listsG.oneOld.same(listsG.mt)); print(" three.same(oneOld): false =? "+listsG.three.same(listsG.oneOld)); print(" three.same(three): true =? "+listsG.three.same(listsG.three)); } } /* There are (about) Two problems with our solutions to the List problem thus far... 1) We have to either - Write a new List/Mt/Cons for every type of list we want to ever have and reimplement them when ever somebody comes up with a new Class to put in a List; or - Write a single list with a general type (Like Object or ISame) and insert a lot of casting whenever we want to do something interesting. 2) We've been adding all of our methods for looking at lists directly to the List classes. Note that usually this is not possible since the List classes would probably be in a library. Solution... 1) Generics! 2) Interfaces for Generic Traversals! I'll sketch these here (Correctly, but with limited Tests because these are getting a little long) but see the next set of Notes (Wednesday) for a full implementation. */ // We Parameterize just about everything over a Generic Type, just like writing a function // to parameterize over its argument. I add a 'G' to all the names of the classes // which will overlap the ones above // This interface is implemented if a class is to be comparable to // any other object, but the implementor must specify a "T" in its definition. interface ISameG{ boolean same(T that); } // Represents a Book/Publication class BookG implements ISameG{ String author; String title; int year; // Create a Book using all information public BookG(String auth, String title, int year){ this.author = auth; this.title = title; this.year = year; } // Needed for the ISame interface public boolean same(BookG that){ return (author.equals(that.author) && title.equals(that.title) && year == that.year); } } // Our Selector interface, but we generalize the type we will be looking at interface ISelectG{ boolean select(T t); } // Represents a generic 'linear' traversal interface Traversal{ boolean isEmpty(); T getFirst(); Traversal getRest(); } // Generic List Union interface AList> extends Traversal, ISameG>{ // We use the double dispatch trick from a while ago boolean sameMt(MtList that); boolean sameCons(ConsList that); // ** Note that isEmpty(), getFirst() and getRest() are also added // (abstractly) to this class by the 'implementation' of Traversal } // Represents an Empty List of T class MtList> implements AList{ // Basic Constructor: Note that if I left this out, the // default constructor would be created, which takes no // arguments. In this case it's actually what we want public MtList(){} // Traversal functions so that things like 'filter' can be // written without disturbing the list classes public boolean isEmpty(){ return true; } public T getFirst(){ throw new RuntimeException("No First Element"); } public Traversal getRest(){ throw new RuntimeException("No Rest Element"); } // We use the double dispatch trick from a while ago public boolean same(AList that){ return that.sameMt(this); } public boolean sameMt(MtList that){ return true; } public boolean sameCons(ConsList that){ return false; } } // Represents a Non-empty List of T class ConsList> implements AList{ T first; AList rest; // Basic Constructor public ConsList(T first, AList rest){ this.first = first; this.rest = rest; } // Traversal functions so that things like 'filter' and 'anySuch' can // also be written without disturbing the list classes public boolean isEmpty(){ return false; } public T getFirst(){ return first; } public Traversal getRest(){ return rest; } // We use the double dispatch trick from a while ago public boolean same(AList that){ return that.sameCons(this); } public boolean sameMt(MtList that){ return false; } public boolean sameCons(ConsList that){ return (first.same(that.first) && rest.same(that.rest)); } } // An ISelect for 'Old' Books class OldBookG implements ISelectG{ public boolean select(BookG b){ return b.year < 1950; } } /* There are more examples and tests in the next set of notes, but this is the Basics... here's a few examples so you can see how they are constructed... see above in the main method for a few 'ISameG' tests. */ // Some Examples of our new Classes // Books are pretty much exactly the same... class BookGExamples{ BookG book1 = new BookG("Jim", "The Oldest Book", 1932); BookG book2 = new BookG("John", "Mid 20th Century", 1947); BookG book3 = new BookG("Julie", "Very Late 20th Century", 1998); BookG book4 = new BookG("Jen", "The Newest book", 2007); } // A few Generic List Examples; Note the construction type parameters class ListGExamples{ AList mt, oneOld, three; ListGExamples(BookGExamples books){ mt = new MtList(); oneOld = new ConsList(books.book2, mt); three = new ConsList(books.book1, new ConsList(books.book4, oneOld)); } }