This homework has two types of problems:
Self Check: You are strongly encouraged to think about and work through these questions, but you will not submit answers to them.
Problems: You will turn in answers to these questions.
The programming problems for this week are in Lab 9.
(Required) Mitchell, Chapter 12.
(Required) Mitchell, Chapter 13.
(As needed) Java and Scala Resources as needed for the programming.
Mitchell, Problem 13.5
Mitchell, Problem 13.3
In C++, a derived class may have multiple base classes. The designers of Java chose not to allow multiple inheritance. Therefore, a Java derived class may only have one base class. However, a Java class may be declared to implement more than one interface. This question asks you to compare these two language designs when consider the following kinds of movies:
Please answer the following:
Draw a C++ class hierarchy with multiple inheritance for the above set of classes.
If you were to implement these classes in C++ for some kind of movie database, what kind of potential conflicts associated with multiple inheritance might you have to resolve?
If you were to represent this hierarchy in Java, what interfaces and classes would you use? Write your answer by carefully drawing a class/interface hierarchy, identifying which nodes are classes and which are interfaces. Note that there must be a class for each of the movie genres, but you may use any interfaces you require to preserve the relationships between genres. For example, one way of doing this would be to have the Comedy and RomanticComedy genres both implement some kind of IComedy interface.
Give an advantage of C++ multiple inheritance over Java classes and interfaces and one advantage of the Java design over C++.
Assuming you will need to create objects of every movie type
(other than Movie), do Scala traits offer a better solution in
this case? Why or why not?
Java does not have general pointer types. More specifically, Java only has primitive types (Booleans, integers, floating point numbers, ...) and reference types (objects and arrays). If a variable has a primitive type, then the variable is associated with a location, and a value of that type is stored in that location. When a variable of primitive type is assigned a new value, a new value is copied into the location. In contrast, variables of reference types are implemented as pointers. When a reference-type variable is assigned, Java copies a pointer to the appropriate object into the location associated with the variable.
Imagine that you were part of the Java design team and you believe
strongly in pointers. You want to add pointers to Java, so that for
every type A, there is a type A* of pointers to values of type
A. Gosling is strongly opposed to adding an "address of" operator
(like & in C), but you think there is a useful way of adding
pointers without adding address-of.
One way of designing a pointer type for Java is to consider A*
equivalent to the following class:
class A* {
private A data;
A*() {
data = null;
}
public void assign(A x) {
data=x;
}
public A deref() {
return data;
}
}
Intuitively, a pointer is an object with two methods, one assigning
a value to the pointer and the other dereferencing a pointer to get
the object it points to. One pointer, p, can be assigned the
object reached by another, q, by writing p.assign(q.deref()).
If A is a reference type, do A* objects seem like pointers
to you? More specifically, suppose A is a Java class with
method m that has a side effect on the object. Consider the
following code:
A x = new A(...);
A* p = new A*();
p.assign(x);
(p.deref()).m();
Here, pointer p points to the object named by x and p is
used to invoke a method. Does this modify the object named by
x? Answer in one or two sentences.
What if A is a primitive type, such as int? Do A* objects
seem like pointers to you? (Hint: Think about code similar to
that in part (a).) Answer in one or two sentences.
If A <: B, should A* <: B*? Answer this question by
completing the following chart and explaining the relationship:
Method Type
------------ ----
A*.assign
B*.assign
A*.deref
B*.deref
d. Can you generalize the issue discussed in part (c) to Java
generics? More specifically, What might happen if you had a
pointer generic? Based on the Ptr example, do you think it is
correct to assume that for every generic class T, if A <: B
then T<A> <: T<B>? Explain briefly.
Type parameters in Scala (and Java) can be given upper and lower
bounds to restrict how they can be instantiated. Specifically, the
type List[_ <: C] describes a list that stores some data of some
type that is a subtype of of class C. In other words, the type
parameter has an upper bound C. For example, an object of
List[_ <: Point] is a list that contains objects which extend the
Point class. For example, the list could be List[Point] or
List[ColorPoint], etc. Reading an element from such a list is
guaranteed to return a Point, but writing to the list is not
generally allowed. This sort of bounded type is often called an
existential type because it can be interpreted as "there exists some
type T such that T <: C."
Existential types can also have lower bound constraints. A
constraint [_ >: C] means that the existential type must be a
supertype of class C. For example, an object of List[_ >: Point]
could be a List[Point] or List[Any]. (Any is the supertype of
all types in Scala, and serves similar purposes as Object in
Java). Reading from such a list returns objects of type Any, but
any object of type Point can be added to the list.
This question asks about generic versions of a simple function that reads elements from one list and adds them to another. Here is sample non-generic code, in case this is useful reference in looking at the generic code below.
def addAllNonGeneric(src: MutableList, dest: MutableList) : Unit = {
for (o <- src) {
dest += o;
}
}
val listOfPoints = new MutableList();
val listOfColorPoints = new MutableList();
...
addAllNonGeneric(listOfColorPoints, listOfPoints);
It will not compile in Scala, but gives you an idea of what we're trying to do.
The simplest generic version of the addAll method uses an
unconstrained type parameter and no bounds.
def addAll0[T](src: MutableList[T], dest: MutableList[T]) : Unit = {
for (o <- src) {
dest += o;
}
}
Suppose that we declare
val listOfPoints : MutableList[Point] = new MutableList[Point]();
val listOfColorPoints : MutableList[ColorPoint] = new MutableList[ColorPoint]();
and call
addAll0(listOfColorPoints, listOfPoints).
Will this call compile or will a type error be reported at compile time? Explain briefly.
With listOfColorPoints and listOfPoints defined as in the
previous part of this question, will the call
addAll1(listOfColorPoints, listOfPoints)
compile, where addAll1 is defined as follows:
def addAll1[T](src: MutableList[_ <: T], dest: MutableList[T]) : Unit = {
for (o <- src) {
dest += o;
}
}
Explain briefly.
With listOfColorPoints and listOfPoints defined as in the
previous part of this question, will the call
addAll2[ColorPoint](listOfColorPoints, listOfPoints)
compile, where addAll2 is defined as follows:
def addAll2[T](src: MutableList[T], dest: MutableList[_ >: T]) : Unit = {
for (o <- src) {
dest += o;
}
}
Explain briefly. (The explicit instantation of T in the call
to addAll2 is needed because of how Scala infers types.)
Suppose that your friend comes across the following general programming suggestion on the web and asks you to explain. What can you tell your friend to explain the connection between the programming advice and principles of subtyping, showing off your understanding gained from CS 334?
Get and Put Principle: If you pass a generic structure to a function:
Use an existential type with an upper bound (ie,
[_ <: T]) when you only GET values out of the structure.
Use an existential type with a lower bound (ie,
[_ >: T]) when you only PUT values into the structure.
Don't use an existential type when you both GET and PUT values out of / into the structure.
Submit your answers to the GradeScope assignment named, for example, "HW 0". It should:
You will be asked to resubmit homework not satisfying these requirements. Please select the pages for each question when you submit.