CS 334
Programming Languages
Spring 2002

Lecture 18


Modules in OO Languages

Details of Java packages and visibility: A class (or interface) belongs to a package if it includes a declaration at the top of the form:

   package SomePackage;

Visibility restrictions in Java: public, default, protected, or private

Public:
visible everywhere its package is in scope.
protected:
visible to any object in the same package or in any subclass.
default:
visible to any object in the same package.
private:
Only visible inside class.

Notes:

  1. If method has param of same type, can see all private features of parameter.

  2. If class not declared to be part of a package then part of the default package.

Problems with packages:

  1. Sometimes tied to directory structure.

  2. Anyone can add to package and get privileged access

  3. All classes/interfaces w/out named package in default package (so all have access to each other!)

  4. No explicit interface for package

  5. Abstraction barriers not possible for interfaces. Discourages use of interfaces for classes.

  6. Abstraction barriers not monotonic:

package A;
public class Fst {
   void m(int k){System.out.println("Fst m: "+k);}
   public void n(){System.out.print("Fst n: "); m(3);}
}

package B;
import A.*;
public class Snd extends Fst{
   public void m(int k){System.out.println("Snd m: "+k);}
   public void p(){System.out.print("Snd p: "); m(5);}
}

package A;
import B.*;
public class Third extends Snd{
   public void m(int k){System.out.println("Third m: "+k);}
}
import A.*;
import B.*;
public class Fourth{
    public static void main(String[] args){
	Fst fst = new Fst();
	fst.n();
			
	Snd snd = new Snd();
	snd.n();
	snd.m(5);
			
	Third third = new Third();
	third.n();
	third.m(7);
	third.p();
    }
}
The output is:
Fst n: Fst m: 3
Fst n: Fst m: 3     // ????
Snd m: 5
Fst n: Third m: 3
Third m: 7
Snd p: Snd m: 5

I obtained the following warning from Metrowerks (a similar warning appears on the FreeBSD UNIX compiler):

Warning : Note: Method void m(int) in class B.Snd does not override the corresponding method in class A.Fst. If you are trying to override this method, you cannot do so because it is private to a different package.
Snd.java line 8 public void m(int k){System.out.println("Snd m: "+k);}

What happened?

Doesn't provide the correct kind of visibility control.

See honors thesis by Leaf Petersen and follow-up work by Joe Vanderwaart and Doug Thunen on modules in LOOM.

Why are statically-typed OOL's so inflexible?

Java programs require lots of type casts (as do C++, Object Pascal, etc.). Why?

The Object class in Java illustrates most of the problems.

    public class Object{
        protected Object clone(){...}
        public boolean equal(Object other){...}
    }

Recall not allowed to change signature of methods in extensions. Also all classes automatically inherit from Object.

    public class A implements Cloneable{
        protected B b = ...;
        ...
        public Object clone(){
            A other = super.clone();
            other.b = b.clone();			// type error
            return other;
        }
    }

    A a1 = new A();
    A a2 = a1.clone();					// type error

Both errors would disappear if could change return types of methods. (OK in C++)

Suppose also want to override equals in A:

	public boolean equal(Object other){
		if (other instanceof A){
			A aother = (A)other;
			return (b = aother.b);
		else
			???

Problems:

If raise exception must declare in method header.

Get similar problems if try to define doubly-linked node as subclass of linked node.

   public void setNext(Node newNext){...}

Want parameter type to be doubly-linked in subclass.

Methods where parameters should be of same type (class) as receiver called "binary methods".

Source of many typing problems in OOL's.

Still other problems:

   public class Circle{
      protected Point center;
	...
   }

If define ColorCircle as extension, might want center to be ColorPoint.

Can't make any of these changes in signature (types) in Java, Object Pascal, and C++ (aside from return type in C++)

Look at the following example:
class A {
   D m(C c) {...}
   void n() {... self.m(someC) ...}
}


class B{
	D' m(C' c'){...}
}

For which C', D' will B end up being type safe if A is?

GJ: Adding F-bounded polymorphism to Java

Odersky, Wadler, et al (follow up to Pizza). Is currently expected(!) to be added to Java 1.5.

GJ adds parametric polymorphism w/ syntax like C++'s templates:

   public class Stack<Elt> extends Vector<Elt>{
      public Elt push(Elt item){...}
      public Elt pop(){...}
      public Elt peek(){...}
      public boolean empty(){...}
      public int search(Elt o){...}
   }

   Stack<Point> myStack = new Stack<Point>();
   Point aPoint = new Point(2,3);
   myStack.push(aPoint);

Can also add constraints to type parameters:

public interface Comparing {
  public boolean equal(Comparing other);
  public boolean greaterThan(Comparing other);
  public boolean lessThan(Comparing other);
}

public class OrderedList< Elt implements Comparing > 
                                extends ... {
  protected Elt[] elts = new Elt[0];

  public void insert(Elt item){...
     while (elts[current].greaterThan(item)) 
        current ++;
     ...
  }
}
  
  public Elt removeFirst(){...}
  public boolean empty(){...}
  public int searchFor(Elt o){...}
}

How to define ordered objects?

public class KeyedObj implements Comparing{
    protected int key ;
    ...;
    public int getKey(){...}
    public lessThan(Comparing other){  
	    return this.key < other.getKey();}
}

Won't work: other.getKey() not well-typed!

    public lessThan(Comparing other){  
	if (other instanceof Comparing)
		return this.key < other.getKey();}
	else
		?????

Same problem as earlier!

F-bounded polymorphism (1989) can help:

public interface Comparing <Elt>{
    boolean lessThan(Elt other);
    boolean greaterThan(Elt other);
}

public class OrderedList < Elt implements Comparing<Elt> >{
  protected Elt [] elts;

  public void insert(Elt newVal){
    while (elts[current].greaterThan(newVal)) 
        current ++;
    ...        
  }
}

public class KeyedObj implements Comparing <KeyedObj>{
  protected int key ;
    ...;
  public int getKey(){  }
  public lessThan(KeyedObj other){  
    return this.key < other.getKey();}
}

Now OrderedList<KeyedObj> is fine!

Generally works well (though confusing at first).

Still one problem -- F-bounded not preserved under subclass:

public class NuKeyedObj extends KeyedObj {
  protected String nuField;
	 ...;
  public lessThan(KeyedObj other){  
    return this.key < other.getKey() && 
                      other.getNuField() ...;}
}

Unfortunately, NuKeyedObj does not implement Comparing .

Can't be used with OrderedList!

Other info on GJ:

Eiffel

Designed by Bertrand Meyer in mid-80's

Class-based OOL w/multiple inheritance

Assertions: pre- and post-conditions, loop invariants and variants built into language.

Supports bounded polymorphism.

Reference semantics like Java, garbage collection, etc.

Information hiding: private, public, or could list classes visible to (like C++'s friends)

No interfaces or modules.

In subclasses, can redefine or even rename methods.

Can also change type of instance variables, parameters and return types covariantly. As we know, this causes type-safety problems!

Introduced "anchor" types: Can declare type to be "like" another feature:

   x: A;
   y: like x;

Currentis Eiffel's name for self.

Example:

class LINKABLE [G]

feature

   item: G;              -- value held
   right: like Current;  -- Right neighbor

   putRight (other: like Current) is
        -- Put `other' to right of current cell.
      do
         right := other
      ensure
         chained: right = other
      end;

end -- class LINKABLE

class BILINKABLE [G] inherit

        LINKABLE [G]
           redefine
              putRight
           end
           
feature -- Access

   left: like Current;   -- Left neighbor

   putRight (other: like Current) is
         -- Put `other' to right of current cell.
      do
         right := other;
         if (other /= Void) then
            other.simplePutLeft (Current)
         end
       end;

    putLeft (other: like Current) is
           -- Put `other' to left of current cell.
        do
           left := other;
           if (other /= Void) then
              other.simplePutRight (Current)
           end
        ensure
           chained: left = other
        end;

feature {BILINKABLE}

   simplePutRight (other: like Current) is 
         -- set `right' to `other'
      do
         right := other
      end;

   simplePutLeft (other: like Current) is
         -- set `left' to `other'
      do
         left := other
      end;

invariant

   rightSymmetry:
      (right /= Void) implies (right.left = Current);
   leftSymmetry:
      (left /= Void) implies (left.right = Current)
      
end -- class BILINKABLE

BILINKABLE is subclass of LINKABLE -- Can't do this with Java, C++, etc., because cannot change type of methods in subclasses in those languages, and don't have a "like Current" construct.

Reason is that covariant changes in types of parameters or instance variable types lead to failure of subtyping (though changes to return types don't cause problems)

Bounded polymorphism

Can define:

   class LINKEDLIST[NODE -> LINKABLE] ...

Can be instantiated with either

Very expressive:

deferred class Comparing
feature
    lessThan(other: like Current): boolean is deferred
    end

    greaterThan(other: like Current): boolean;
end

Unfortunately, use of like Current gives rise to implicit covariant change to types of instance variables and method parameter and return types.

Thus BILINKABLE is not a subtype of LINKABLE. Though BILINKABLE is internally consistent.


Back to:
  • CS 334 home page
  • Kim Bruce's home page
  • CS Department home page
  • kim@cs.williams.edu