Homework 4: Sentinel Lists

Homework is important practice for you, but it’s not graded so you don’t have to submit it. This particular homework has you test and refactor a “bad” implementation of the List interface; you’ll also get to reflect a bit.

Testing Lists

On Piazza you’ll find the List interface we developed in lecture as well as a “bad” implementation called LinkedList.

Before you do anything else, you should develop a set of JUnit 4 test drivers for the List interface. Put all the general test cases for the List interface into an abstract class ListTestBase.java; any specific test cases for LinkedList should go into a concrete class LinkedListTest.java which inherits from ListTestBase as usual. (Eventually you’ll want a SentinelListTest.java as well of course, see below.)

Be sure to test all methods and be sure to test all exceptions for error situations as well. Ideally you will make a complete set of tests before you start working on the SentinelList code.

Hints

What are sentinels?

The LinkedList class follows the basic pattern for linked lists we’ve used from the beginning of the course:

The result of this organization is that our code for modifying the list has to constantly check whether this, that, or the other thing is null and react accordingly. The code is full of conditionals where we do one thing for a null reference and another thing for a non-null reference. In other words it’s horrible.

The idea for SentinelList is to change all that, to remove (almost) all the case distinctions around null references. To do that we start from a simple premise, however that premise does take some getting used to:

Let this sink in for a little while, then draw some examples, starting with the empty list. As you’ll see, every insertion operation will now happen between two nodes, and there’s no longer any need to deal with null references. That’s where the big simplification comes from!

Note that if you don’t actually sit down and try this out with a piece of paper (or a whiteboard) you’ll never get it. We’re not kidding, Peter has literally stacks of pages with scribbled little list diagrams sketching the “before” and “after” situations for the various List operations. That’s what you want to have too before you hack the code!

Refactoring LinkedList

Copy LinkedList.java to SentinelList.java and start refactoring! Your primary goal is to replace the existing “null marks the ends” representation used by LinkedList with one that uses sentinel nodes instead.

Your secondary goal is to make the code as simple and concise as you possibly can. This will require that you find patterns in the existing code (primarily around insertion and removal) that can be “unified” into private helper methods; ideally the “many” public methods will mostly be reduced to one-liners that call the “few” private helpers. Note that the best patterns will only emerge after you have sentinels in.

Don’t Repeat Yourself!

Pay extra attention to avoiding duplicated code! (You want DRY and not WET code!) Here are a few examples of what we mean by that:

The goal is to end up with a List implementation that’s both simpler and more concise than what we gave you to start with.

Hints

Reflection

This is not a programming problem; it’s a thinking and writing problem. (It’s practice for the kind of thing you’re likely to face in an interview.) Write a reflection on the design we’ve come up with: The List interface itself and the Position interface clients use to “talk about” places in the data structure without “knowing” what those places really are. Here are some things you could write about, although there are probably a lot more:

Feel free to take your reflection in any direction you think is useful, the points above are simply suggestions. We certainly won’t “get mad” if you tell us that our List interface is really bad, just as long as your reasoning is sound. You want to convince us that you can think and write coherently about programming independently of actually doing it!

Artifacts

At minimum, you should have the file SentinelList.java containing your shiny new list implementation of pure awesomeness as well as the necessary files for your test cases (all three of those). And of course all the various supporting classes and interfaces needed to recompile everything. Everything should compile without warnings with the -Xlint:all flag; there should be no checkstyle warnings either with the 601.226 configuration file posted on Piazza. Your reflection should be in your README file.