/**
    Classes in Java serve a dual role as collections of fields and methods and
    as types for the objects of that class.  Strictly speaking, each class C
    introduces a type instance_type(C) of the objects of that class.

    Instance types are essentially interfaces --- they describe the public
    components of an instance of a class.  However, in Java instance types are
    given a "nominal", rather than "structural" interpretation.  In
    particular, two classes producing instances with the same public
    components determine distinct object types.

    Java supports subtyping --- if T is a subtype of U, then any value of
    type T is also a value of type U.  Put another way, a value of type T
    suffices whenever a value of type U is required.

    The subtyping relation in Java is tied to the class hierarchy.  Rather
    than interpret subtyping structurally (based on the types of the
    components), Java restricts instance_type(C) to be a subtype of
    instance_type(D) iff C is a subclass of D, ie iff C inherits from D.

    Interfaces may be thought of as completely abstract classes (with no
    code).  If a class C implements interface I, then instance_type(C) is a
    subtype of instance_type(I).  Thus an instance of C may be used wherever
    an object with interface I is required.

    The subtype relation on interfaces is also nominal, rather than
    structural.  One interface I is a subtype of another J iff I inherits from
    (extends) J.

    The subtype relation can be inverted using "downcasting".  If V is a value
    of class D and C is a sub-class of D, then we can downcast V to C by
    writing (C)V.  A run-time check ensures that the value really is a value
    of the subclass.  This is achieved by attaching a representation of the
    class to each object so that a class check can be performed at run-time,
    a time and space overhead.

*/

/* Interface of points in the plane. */
interface POINT {
  public int x_pos ();
  public int y_pos ();
  public void bump ();
}

/* Class of points in the plane. */
class Point implements POINT {
  private int x, y;

  public int x_pos () {
    return this.x;
  }
  public int y_pos (){
    return this.y;
  }
  public void bump () {
    this.x++; this.y++;
  }
  public Point (int initx, int inity) {
    this.x = initx; this.y = inity;
  }
}

/* Interface of colored points --- points, plus a color field. */
interface COLORED_POINT extends POINT {
  public int color ();
}

/* Sub-class of colored points. */
class ColoredPoint extends Point implements COLORED_POINT {
  private int color;

  public int color () {
    return this.color;
  }
  public ColoredPoint (int initx, int inity, int initcolor) {
    super (initx, inity);
    this.color = initcolor;
  }
}

class SubtypeDemo {

  private static void bump_twice (POINT p) {
    p.bump(); p.bump();
  }

  public static void main (String argv[]) {
    Point p = new Point (0, 0);
    ColoredPoint cp = new ColoredPoint (0, 0, 1);
    
    /* Every Point is a POINT. */
    bump_twice (p);
    /* Every ColoredPoint is a COLORED_POINT is a POINT. */
    bump_twice (cp);

    /* Move up and down the hierarchy. */
    Object x = p;		// forget that p is a Point
    Point q = (Point) x;	// downcast back to Point
    Point r = cp;		// forget that cp is a ColoredPoint
    ColoredPoint s = (ColoredPoint) r; // downcast back to ColoredPoint
    ColoredPoint t = (ColoredPoint) p; // fails at run-time! p is not colored

  }

}
