Assignment 3, CSCI 5535

Due date: October 18th

  1. Rather than using the term "subtyping" the Java programming language uses the term "widening" and "narrowing" conversions, where there is a widening conversion from a subtype to a supertype and a narrowing conversion from a supertype to a subtype.  Of course, narrowing conversions must be checked at run time to make sure that they are type safe.  Section 5.1.5 in the Java language definition (available in the interesting links section of the class web page) gives the narrowing reference conversions for Java.  In other words, the narrowing conversions for reference types (classes, interfaces, and arrays). 
    1. For each of the narrowing reference conversion rules give an example code segment that illustrates a successful narrowing conversion using that rule. 
    2. Explain why this conversion is allowed only when there is "...no method m such that..." in this rule: "From any interface type J to any interface type K, provided that J is not a subinterface of K and there is no method name m such that J and K both contain a method named m with the same signature but different return types"

    Note that before you are able to answer this question you will need to have a good understanding of how interfaces work in Java and the meaning of "final".

  2. C++'s template mechanism also gives "parametric polymorphism" similarly to generics in GJ.  Can the generics/templates be typechecked once and then instantiated (e.g., List<Shapes>) many times?  Or do they need to be typechecked multiple times?  If your answer is the latter (need to be typechecked multiple times) then give an example to illustrate this.
  3. From the Smalltalk paper we see that if and while statements look as follows:

    queue isEmpty ifTrue:[index<- 0]

    [index <= limit] whileTrue: [index <- index + 1]

    Why is it that the receiver of the ifTrue: message is a Boolean object (i.e., the result of  "queue isEmpty") whereas the receiver for the whileTrue: is a block?  Explain the impliciations of this difference.

  4.  Modula-3 provides a different mechanism, called opaque types, for information hiding than the public/private/protected mechanism in C++ and Java.  An opaque type may be declared as follows:

    TYPE T <: U

    It says that Type T is a subtype of U.  However, it does not say which subtype.  A programmer may use this type, just like any other type:

    VAR x: T := NEW (T);

    The information hiding comes from the fact that the above code can only use x as a U object.  In particular, we can invoke methods and access instance variables that are known to be in U, but not any new methods/instance variables that T adds.  Thus, the additions of T are hidden.  Generally, Modula-3 programs put the opaque type declarations in interfaces (which are similar to header files in C++ and C).

    Now, somewhere, the program must reveal what T really is (as opposed to just being some subtype of U).  This is done using a REVEAL declaration that takes one of two forms:

    REVEAL T = some type that is a subtype of U, or

    REVEAL T <: some type that is a subtype of U

    The first form says exactly what type T is.  Of course, in order to be consistent with T's original opaque declaration, that type must be a subtype of U.  This kind of a revelation is called a concrete revelation since it fully reveals the type of T.  Concrete revelations are usually put in Modules (equivalent of .c or .cpp files in C or C++) and not in Interfaces.  The reason for this is that the contents of Interfaces are visible to other Interfaces and Modules whereas the contents of a Module are not visible outside the Module.

    The second form reveals some additional information about T but not the full information.  Thus, it is called  a partial revelation.  For example, it may reveal that T has one additional method (besides the methods inherited from U).  Any code that has access to this partial revelation knows about the additional method in T besides the methods inherited from U.  In other words, this mechanism allows a programmer to reveal information about a type in multiple stages (perhaps some revelations are meant for "friends" while others for the "general public").

    In this question you will get experience understanding and evaluating Modula-3's opaque types.  Note that you may refer to the Modula-3 language definition (available from the class web page) to answer these questions.

    1. Let's suppose I want to write a stack package.  Moreover, let's suppose that a stack has the methods, push, pop, count, and instance variables, body and top.  I want to make the public interface of the stack package only contain two things: push and pop.  However, I want the stack package to interact with another package that I'm writing.  That package needs to know not just about the push and pop methods but also about the count method.  Give the opaque type declarations and revelations that accomplish the above information hiding.  Explain where you will put the various declarations and revelations  (i.e., which interface or module).
    2. Compare opaque types as an information hiding mechanism to Java's information hiding mechanism (more specifically the private, public, and protected declarations--ignore Java interfaces for this question).  Base your arguments on (i) Expressiveness: which mechanism gives you most flexibility in determining information hiding? (ii) Simplicity: which mechanism is simpler to understand and use; (iii) Compactness: which mechanism allows you to hide information with the least amount of code.  Support your arguments with examples.