On this page:
1 Warmup:   generic methods on generic lists
2 Visitors for lists
3 Visitors for ancestor trees
6.8

Lab 7: Parametric data and visitors

Goals: The goal of this lab is to practice working with parametric data types and with visitors.

Related files:
  tester.jar  

1 Warmup: generic methods on generic lists

Start a new project, and copy into it the following definitions of IList<T> and its supporting classes.

interface IList<T> {
// TODO: add your methods here }
 
class MtList<T> implements IList<T> {
// TODO: add your methods here }
 
class ConsList<T> implements IList<T> {
T first;
IList<T> rest;
 
ConsList(T first, IList<T> rest) {
this.first = first;
this.rest = rest;
}
 
// TODO: add your methods here }

Design the append method that takes this list and a given list and produces the result of appending the latter onto the former.

Design the map and filter methods for lists. (We’ve done at least one of those in class!) The definition of IFunc below may be useful.

interface IFunc<A, R> {
R apply(A arg);
}
2 Visitors for lists

Design a visitor for lists:
  • Define a IListVisitor interface. How many type parameters will it need? (Hint: how many type parameters did the IShapeVisitor from class need, compared to how many type parameters IShape itself needed?) What methods will the visitor need? (Hint: what methods did the IShapeVisitor need, and how did that relate to the classes we had that implemented IShape?) Name all your methods visit(...) this is another example of overloading.

  • Define a method ?????? accept(IListVisitor<??????> v) on IList<T>, and implement it on the classes implementing IList<T>. Fill in the question marks with whatever type parameter(s?) are needed.

Design a MapVisitor for lists. This visitor should behave just like the map method does: here’s an example that takes a list of Books and produces a list of their titles:
IList<Book> someBookList = ...
IFunc<Book, String> bookTitle = new BookTitle();
MapVisitor<??????> mapBook2TitleVisitor = new MapVisitor<??????>(???)
 
t.checkExpect(someBookList.map(bookTitle), someBookList.accept(mapBook2TitleVisitor));

Complete this example, copying in the definition of Book from below, implementing the BookTitle function object for mapping lists of books to lists of titles, and confirming that the example works as expected. Fill in the question marks with whatever type parameter(s?) are needed.

// to represent a book in a bookstore class Book {
String title;
String author;
int price;
 
Book(String title, String author, int price) {
this.title = title;
this.author = author;
this.price = price;
}
}

Think of another example of mapping a list of books to a list of some other type. Implement and test that example mapping using the MapVisitor.

Design a FilterVisitor for lists. Construct a similar example that filters the list to find all books with a price less than 50, and test that your visitor and your filter method behave equivalently. Think of another example of filtering a list of books, then implement and test that filter using the FilterVisitor.

3 Visitors for ancestor trees

Copy the IAT interface and related classes from below into your project.

interface IAT {
}
class Unknown implements IAT {
Unknown() { }
}
class Person implements IAT {
String name;
int yob;
boolean isMale;
IAT mom;
IAT dad;
Person(String name, int yob, boolean isMale, IAT mom, IAT dad) {
this.name = name;
this.yob = yob;
this.isMale = isMale;
this.mom = mom;
this.dad = dad;
}
}

Design a visitor for IATs: define an IATVisitor interface, add an accept method to IAT, and implement it on the relevant classes.

Design an IATVisitor that takes an IAT and produces a IList<String> of the names of the people in the IAT. (Hint: you will probably want to use the append method you designed earlier!)