Assignment P4#

Applies to:COMP6710
Released by:Monday, 14 April 2025, 09:00
Base assignment deadline:Friday, 25 April 2025, 15:00
Code Walk registration deadline:Friday, 25 April 2025, 18:00
Code Walk registration link:CWAC
Code Walks:
Thursday, 01 May 2025
Friday, 02 May 2025
GitLab template repository:(link)
GitLab CI file:.gitlab-ci.yml
Minimum Library Version:2025S1-7
Last Updated:Friday, 25 April 2025, 14:35

This assignment uses regular Java 23, and JUnit Jupiter 5.9.0. You may optionally import the Functional Java Standard Libraries. Do not import other libraries into your project. Your code may not:

  • Explicitly throw exceptions, or annotate methods with a throws clause, except where explicitly permitted
  • Catch exceptions outside of the allowed pattern for reading/writing files (see Slides of Workshop 6B).
  • Use concurrency (if you do not know what that is, you will not be using it so long as you write the code on your own).
  • Use reflection (if you do not know what that is, you will not be using it so long as you write the code on your own).
  • Interact with the environment outside of the file system operations described on the Slides of Workshop 6B.
  • Write to or read from files other than described in the assignment.

In everything you do, you must follow the Design Recipe. The minor adjustments to the Design Recipe for class definitions are available in Slides of Workshop 6B To see roughly how this assignment will be marked, check out the Skeleton Rubric.

You still need to follow the Design Recipe and write appropriate documentation and tests. In particular, the (minor) adjustments to the Design Recipe for class definitions were covered in workshop 6B. Do not write code that is overly complicated.

Formalities#

This assignment is submitted via GitLab.

Access to Your Repository#

In order for us to be able to collect and mark it, you need to satisfy the following conditions:

  • Your repository’s name must be comp6710-2025s1-p4 (exactly), placed directly in your user namespace (the default). That is, if your uid is u1234567, the address of your GitLab project should read as https://gitlab.cecs.anu.edu.au/u1234567/comp6710-2025s1-p4.
  • Your repository must have our marker bot (comp1110-2025-s1-marker) added as a Maintainer.

You can achieve both these points by creating your project through forking our template repository and not changing the name, or by just using the correct name when creating the project and then manually adding the bot.

Notebooks and Push Requirement#

You need to keep a notebook file as explained on the Git and Notebooks page. You need to commit and push the current state of your files:

  • at the end of every session where you work on the assignment
  • at least once per hour (our checks implement this that no two pushes during sessions recorded in the notebook are more than 70 minutes apart).
  • at least once per major part of the assignment (i.e. for this assignment, at least four times). You are absolutely free to commit and/or push more often than that.

You need to write informative commit messages, and informative notes for each session in your notebook, which describe what it is that you did for this particular commit or session, respectively.

Statement of Originality#

Your submission (and therefore your git repository) needs to include a signed statement of originality. This must be a text file named soo.txt. That file must contain the following text, with the placeholders [your name here] and [your UID here] replaced with your name and UID (remove the brackets!), respectively:

I declare that this work upholds the principles of academic
integrity, as defined in the University Academic Misconduct
Rule; is entirely my own work; is produced for the purposes
of this assessment task and has not been submitted for
assessment in any other context, except where authorised in
writing by the course convener; gives appropriate
acknowledgement of the ideas, scholarship and intellectual
property of others insofar as these have been used; in no part
involves copying, cheating, collusion, fabrication, plagiarism
or recycling.

I declare that I have not used any form of generative AI in
preparing this work.

I declare that I have the rights to use and submit any assets
included in this work.

[your name here]
[your UID here]

Files Summary#

Your repository must be accessible to us and must have the following structure:

  • notebook.yml - your Notebook
  • soo.txt - your signed Statement of Originality
  • src - a folder containing your source files:
    • ConsListList.java - containing your work for parts 1-4
    • Box.java - containing part of your work for part 5
    • BlackBox.java - containing part of your work for part 5
    • WhiteBox.java - containing part of your work for part 5
    • GreyBox.java - containing part of your work for part 5
    • ColouredBox.java - containing part of your work for part 5
  • tests - a folder containing your test files:
    • ConsListListTests.java - containing your tests for parts 1-4
    • BoxTests.java - containing all your tests for part 5

You may have additional files in src for additional classes, and additional files in tests for additional tests.

Project Configuration and Running Programs#

We recommend that you use IntelliJ IDEA for this assignment. However, you do not have to. If you do, the standard settings that result from following the IntelliJ Project Setup Guide should make your project work with our testing environment.

If you do not want to (or cannot) use IntelliJ IDEA, or if you want to make sure you can run your program like our automated testing framework, then you can follow the guide available here. This will allow you to trigger your tests directly from the console, in a similar way we did in the first half of the course with the functional Java library support for tests.

Info: Java Standard Libraries#

Part of this assignment asks you to do things for which there are operations in the Java Standard Libraries. Consider particularly looking at the following pages:

Tasks#

In most of the parts of this assignment, you will create an implementation of the standard Java List interface using singly-linked lists. You can either use the Functional Java Standard Library’s implementation of ConsList as the underlying data type, or implement your own singly-linked list.

It is important, however, that the underlying data structure is a singly-linked list, and that you implement the relevant parts of the list interface. No partial marks will be awarded, and your code walk marks will be 0, if you do NOT satisfy this requirement!

Start with the following class declaration in a file called src/ConsListList.java:


public class ConsListList<T> implements List<T> {

}

IntelliJ IDEA will underline this with a squiggly red line, showing you that there are some problems there. You can right-click this underlined part and select “Show Context Actions”, which will get you to a sub-menu, where you can select “Implement methods”. This will show you a window where you can select a list of methods to implement - use the already-pre-selected list, and check the box to “Copy JavaDoc” at the bottom, like so:

The window to select methods to implement for List<T> in IntelliJ IDEA

This should fill your file with many methods and comments, which will for the basis for most of the rest of the assignment. Use the comments for the methods to tell you what the method is supposed to do. While there are generic types involved here, you can just as well think of T as Object (but leave the signatures untouched)!

Part 1#

In the file src/ConsListList.java

Part 1 is a regular part of the assignment and will be included in marking it. However, it is designed as an on-ramp. Tutors may help you with the code here if you ask for help - though you should still try to do as much as possible yourself.

Add the following constructor to ConsListList:

/**
 * Creates a new empty ConsListList
 */
public ConsListList()

Implement the following methods (and add the relevant parts of the Design recipe to the comments):

  • add(T t)
  • remove(Object o)
  • size()
  • isEmpty()
  • get(int index) throws IndexOutOfBoundsException
  • set(int index, T t) throws IndexOutOfBoundsException

Follow the Design Recipe!

The last two methods have throws clauses, which means that you may add those clauses to your method header, and any relevant helper methods, and you may put the throw statement throw new IndexOutOfBoundsException(); at relevant points in your code.

Part 2#

In the file src/ConsListList.java

Implement the following methods (and add the relevant parts of the Design recipe to the comments):

  • contains(Object o)
  • containsAll(Collection<?> c)
  • removeAll(Collection<?> c)
  • retainAll(Collection<?> c)
  • clear()
  • add(int index, T element) throws IndexOutOfBoundsException
  • remove(int index) throws IndexOutOfBoundsException
  • indexOf(Object o)
  • lastIndexOf(Object o)

Follow the Design Recipe!

The add(int,T) and remove(int) have throws clauses, which means that you may add those clauses to your method header, and any relevant helper methods, and you may put the throw statement throw new IndexOutOfBoundsException(); at relevant points in your code.

Note, the generic argument ? means that you can essentially only read Objects from the collection, and not write to it.

Part 3#

In the file src/ConsListList.java, and potentially additional files

Implement the following methods:

  • iterator()

Follow the Design Recipe!

This requires you to implement the Iterator<T> interface with some class. It may be beneficial to implement this iterator as a (static) inner class to ConsListList, like so:

public class ConsListList<T> implements List<T> {
    private class ConsListIterator implements Iterator<T> {
        ...
    }
    ...
}

You should implement this iterator on your own, and not use the iterator from ConsList<T> in the Functional Java Standard Library. Implement in particular the following two methods:

  • hasNext()
  • next() throws NoSuchElementException

Follow the Design Recipe!

next() may use the statement throw new NoSuchElementException(); . It may also, even though it would not be declared in a throws clause, use the statement throw new ConcurrentModificationException();, to indicate that a list has been modified since the the iterator was created, and as such the iterator has become invalid (see also ConcurrentModificationException). You do not have to test for these exceptions - if your code is implemented correctly, it will never throw the exceptions for the tests that we will run, and you can assume that the methods will always be called with correct arguments and in the correct state and sequence.

Part 4 (Distinction-Level)#

In the file src/ConsListList.java, and potentially additional files

Implement the following methods:

  • subList(int fromIndex, int toIndex) throws IndexOutOfBoundsException

Follow the Design Recipe!

This will likely need you to create another class implementing the List<T> interface, which you can put in its own file or also make an inner class for. It should support the same operations as all the parts we asked you to implement above.

Follow the Design Recipe!

The method has a throws clause, which means that you may add that clause to your method header, and any relevant helper methods, and you may put the throw statement throw new IndexOutOfBoundsException(); at relevant points in your code.

Part 5 (Distinction-Level)#

In this part, you need to copy the below interface, and implement exactly four classes with exactly the members of the interface and the additional members described for each class, where applicable. This is rather easy to do, but not the focus of this part, which is on the subtyping and inheritance relationships. Make sure to be very careful and precise about the pre- and postconditions, and invariants, for each class and method. There is exactly one correct solution, which you need to find here and then be able to explain in the code walk.

You are given the following interface:

/**
 * Represents rectangular boxes consisting of printable 
 * characters. A box has a frame and an interior, and 
 * a frame character to represent the frame of the box
 * when printed.
 */
public interface Box {
    /**
     * Writes several lines representing this box
     * to the standard output. At minimum, this means
     * drawing frame characters along the box's outline.
     */
    void print();
    /**
     * Sets the size of the frame of the box
     * Effects: the box now has the given width and height
     * @param width The width of the box, 3 <= width <= 40
     * @param height The height of the box, 3 <= height <= 10
     */
    void setSize(int width, int height);

    /**
     * Sets the character to be used to draw the frame 
     * of the box in future calls to the print method.
     * Effects: the box now uses the given character as
     *   its frame character
     * @param frame the new frame character
     */
    void setFrameChar(char frame);
}

The interface only describes parts of what we want to do with boxes, so we will show examples for the particular classes you need to implement:

  • Implement a class BlackBox, which, when printed uses the frame character to fill the whole rectangle. That is, a 6x4 BlackBox with frame character ‘#’ should print as:
    ######
    ######
    ######
    ######
    

    The class should have the following constructor:

    BlackBox(int width, int height, char frame)
    
  • Implement a class WhiteBox, which when printed always uses spaces ‘ ‘ to fill the rectangle inside of the frame. That is, a 6x4 WhiteBox with frame character ‘#’ should print as:
    ######
    #    #
    #    #
    ######
    

    The class should have the following constructor:

    WhiteBox(int width, int height, char frame)
    
  • Implement a class GreyBox, which has a constructor that allows picking a fill character separately from the frame character, but only in the constructor. Once constructed, a GreyBox should not be able to change its fill character. A 6x4 GreyBox with frame character # and fill character @ should print as:
    ######
    #@@@@#
    #@@@@#
    ######
    

    The class should have the following constructor:

    GreyBox(int width, int height, char frame, char fill)
    
  • Implement a class ColouredBox, which is similar to GreyBox, except that it has an additional method setFillChar(char fill) to set the fill character later. The class should have the following constructor:
    ColouredBox(int width, int height, char frame, char fill)
    

    Follow the Design Recipe!

When implementing these classes, be particularly careful about pre- and postconditions, and invariants. You must use inheritance relationships exactly where there are appropriate subtyping relationships. Heavy deductions in marks apply where you do not declare a potential inheritance relationship, and heavy deductions in marks also apply where you declare an inheritance relationship where there is no correct subtyping relationship.

For each subtyping relationship that you think exists, write tests that show that the substitution principle applies. For each subtyping relationship that you think does not exist, write a test for the potential superclass and write a comment that explains how the other classes could not be subtypes in that case.


Part 5 was adapted from a course created by Franz Puntigam, though anything that is wrong with it is our fault.

Updates#

Saturday, 19 April 2025, 08:55Fixed a typo in the requirements note of the Tasks section
Monday, 21 April 2025, 21:45Added allowed throws clauses to add(int,T), remove(int), and subList
Friday, 25 April 2025, 14:35Added CI file without interface tests
bars search caret-down plus minus arrow-right times