CS 303E: Assignment #1000 (Fall 2004)
Inheritance and Packages (150 Points)

Due: Sunday evening, November 14 by midnight via turnin. If you have problems with turnin from outside the Elements Lab, be sure to use turnin from the Elements Lab so that you submit your work on time.

New Requirement: Starting with this assignment, your Java class definitions should all be placed into package "edu.utexas.cs303e.student" or, when explicitly stated, a sub-package thereof. If an exercise does not explicitly state the package, you should place it into edu.utexas.cs303e.student. For example, if an exercise asks you to place your implementation into a "class named AnArbitraryName", your source code should define a class which has full name edu.utexas.cs303e.student.AnArbitraryName.

Purpose: This assignment gives you practice with inheritance and packages. In particular, you will be asked to define collaborations of multiple classes in certain exercises. A collaboration is a group of classes that are expected to work together.

Remember: If you aren't clear on a topic covered in this class, you can post on the class newsgroup or you can attend the many office hours held by the teaching staff. In particular, if you're not clear on any of the terms or concepts described in this assignment, please ask questions. The earlier you ask your questions, the better!

Part 1: Inheritance Basics. In this part, your overall task is to implement an inheritance hierarchy to represent words that are cognate to English words. Even though there are stricter definitions of "cognate", we'll simply define it as follows: A word in one language is a cognate of a word in another language if they have the same meaning. For example, the French word "pied" is a cognate of the English word "foot".

  1. (20 points) Start by implementing an immutable (no mutators!) class named Word that contains an attribute representing a word that you might use in a sentence. Be sure to define an appropriate instance variable for this attribute. (What package should you use to define this class?) Class Word must have one public constructor and two public methods as defined below:

    In addition to the public constructor and methods defined above, you may also define as many protected methods as you want. Such methods are not necessary in this exercise, but well-chosen protected methods might help you to implement some of the other exercises in this assignment.

    Put your class definition into a file named Word.java and submit it via turnin.

  2. (45 points) Next, implement an immutable (no mutators!) class named CognatePair (in which package?) that extends Word. Instances of this class will define a pair of words, one in English and the other in another language. The two words will be cognates. Your implementation should have exactly one constructor:

    As a result, your CognatePair class will have two attributes: The word defined in the superclass, and a new cognate attribute representing the cognate word defined in this class. Based on this information so far, it should seem reasonable to you that your CognatePair class will have an accessor method for each word:

    However, there will also be another accessor, public String getCognateLanguage(). This will return the language of the cognate word in each instance. In your source code for the CognatePair class, implement this method as follows:

    public String getCognateLanguage() {
        throw new IllegalStateException ("not implemented") ;
    }
    

    This accessor will be overridden with a new definition in each subclass of CognatePair. The overriding definition will return an appropriate language (more on that in later exercises).

    Finally, you should provide a public String toString() implementation that returns a String formatted as follows:

    <language> word "<cognate>" means "<word>" in English
    where <language> is replaced with the language of the cognate, where <cognate> is replaced with the cognate itself, and where <word> is replaced with the English word. For example, if the language of the cognate is French, the English word is "fish", and the cognate is "poisson", then toString() should return:
    French word "poisson" means "fish" in English

    It may seem hard to test class CognatePair since you can't call the constructor from BlueJ. However, for debugging purposes only, you may implement a standard main method in CognatePair to create and test instances of CognatePair. This is possible because the main method will be in the same class as the protected constructor and, therefore, will be able to access the constructor.

    Put your class definition into a file named CognatePair.java and submit it via turnin.

  3. (15 points) Ok, now it's time to actually make use of the above classes. For one use, define a class named FrenchCognate in package edu.utexas.cs303e.student.french. This class extends your class CognatePair defined above (remember to import CognatePair). The subclass FrenchCognate will define one constructor and one method as described below:

    At this point, you should be able to test class FrenchCognate in BlueJ using FrenchCognate's constructor. This will further test classes CognatePair and Word. Why?

    Put your class definition into a file named FrenchCognate.java and submit it via turnin.

  4. (25 points) As another use of class CognatePair define a class named PigLatinCognate in package edu.utexas.cs303e.student.pig_latin. This class again extends your class CognatePair defined above (remember to import CognatePair). It will define one public constructor, one public method, and one private method as described below:

    At this point, you should be able to test class PigLatinCognate in BlueJ using PigLatinCognate's constructor.

    Put your class definition into a file named PigLatinCognate.java and submit it via turnin.

Part 2: Word Collaborations. Words are typically combined into phrases and sentences, so it should seem reasonable that we would want to define classes that combine multiple Word instances as defined in Part 1. In this part, you're asked to define a class Phrase that combines Word instances. In the implementation, you'll see another use of recursion.

The simplest kind of phrase contains only one word. For example, the phrase "Arghh" might indicate frustration. On the other hand, phrases with multiple words can be viewed as a combination of a leading word and a suffix phrase. For example, the phrase "Eighty percent of success is showing up" (attributed to Woody Allen) can be viewed as the combination of the leading word "Eighty" and the suffix phrase "percent of success is showing up". This is where recursion shows up: We're defining a multi-word phrase to be a combination of a word and a suffix phrase, which may again be a multi-word phrase. So the definition of "phrase" recursively depends on itself. We'll make use of this type of recursion in the definition of class Phrase below.

  1. (45 points) Define an immutable class Phrase (in which package?) with the following constructors and methods:

    When testing your implementation, be sure to test both single-word and multi-word phrases. For example, the following code should define several multi-word phrases, and the last one, in variable eighty, should be the entire "Eighty percent..." quote from Woody Allen. The code shown should print the quote as it is built word-by-word. The last line printed should show the entire quote. If you use this code as part of your testing, be sure to import the referenced classes.

    Phrase up = new Phrase (new PigLatinCognate ("up")) ;
    System.out.println (up) ;
    Phrase showing = new Phrase (new PigLatinCognate ("showing"), up) ;
    System.out.println (showing) ;
    Phrase is = new Phrase (new PigLatinCognate ("is"), showing) ;
    System.out.println (is) ;
    Phrase success = new Phrase (new PigLatinCognate ("success"), is) ;
    System.out.println (success) ;
    Phrase of = new Phrase (new PigLatinCognate ("of"), success) ;
    System.out.println (of) ;
    Phrase percent = new Phrase (new PigLatinCognate ("percent"), of) ;
    System.out.println (percent) ;
    Phrase eighty = new Phrase (new PigLatinCognate ("Eighty"), percent) ;
    System.out.println (eighty) ;
    

    Note: It's perfectly legal to use a PigLatinCognate as a Word argument in the constructors to Phrase, as shown above. Why?

    Put your implementation of Phrase into a file named Phrase.java and submit it via turnin.

That's all you have to do for this assignment. However, you should probably also think about the following problem: What should you do if you want to implement a CognatePhrase class which has a toString() method that prints each instance in its cognate language? We'll revisit this problem in the future.