(class Point Object
  ; OVERVIEW: the abstract value of a point can be described in Prolog (!)
  ; as a term of the form
  ;       (point x y)
  ; where x and y are numbers.  That is we have
  ;       (infer (is-point (point X Y)) from (is-number X) (is-number Y))
  ; We can think of the following as specifying how the abstract values behave
  ; abstractly:
  ;       (infer (x-coordinate (point X Y) X))
  ;       (infer (y-coordinate (point X Y) Y))
  ;       (infer (quadrant (point X Y) 1) from (<= 0 X) (<= 0 Y))
  ;       (infer (quadrant (point X Y) 2) from (<= 0 X) (<= Y 0))
  ;       (infer (quadrant (point X Y) 3) from (<= X 0) (<= 0 Y))
  ;       (infer (quadrant (point X Y) 4) from (<= X 0) (<= Y 0))
  ;
  (xCord yCord)
  ; REP INVARIANT: true
  ; ABSTRACTION FUNCTION: self represents the abstr. value (point xCord yCord)

  (define initPoint (x y)
     ; TYPE: Point, Int, Int -> Point
     ; REQUIRES: the caller is mkPoint
     ; EFFECT: change the state of self to be (point x y), and return self
     ; In Prolog we would specify this relationship as
     ;      (infer (initPointRel (point PreX PreY) I J (point I J)))
     (begin
       (set xCord x)
       (set yCord y)
       self))

  (define abscissa ()
     ; TYPE: Point -> Int
     ; EFFECT: return the x-coordinate of self
     xCord)
  (define ordinate ()
     ; TYPE: Point -> Int
     ; EFFECT: return the y-coordinate of self
     yCord)
  (define reflect ()
    ; TYPE: Point -> Void
    ; EFFECT: reflect self through the line x = -y
    ; In Prolog we would specify this as
    ;       (infer (reflectRel (point X Y) (point NX NY))
    ;         from (sub 0 X NX) (sub 0 Y NY))
    (begin
      (set xCord (- 0 xCord))
      (set yCord (- 0 yCord))
      self))
  (define rotate ()
    ; TYPE: Point -> Void
    ; EFFECT: rotate self 90 degrees clockwise
    ; In Prolog we would specify this as
    ;       (infer (rotateRel (point X Y) (point Y NX))
    ;         from (sub 0 X NX))
    (rotate-aux self xCord))
  (define rotate-aux (temp)
    (begin
      (set xCord yCord)
      (set yCord (- 0 temp))
       self))
  (define compare (p2)
    ; TYPE: Point, Point -> Bool
    ; EFFECT: is self closer to the origin than p2?
    (< (sqrdist self) (sqrdist p2)))
  (define sqrdist ()
    ; TYPE: Point -> Int
    ; EFFECT: return the sum of the squares of the x and y coordinates of self
    (+ (sqr xCord) (sqr yCord)))
  (define quadrant ()
    ; TYPE: Point -> Bool
    ; EFFECT: return the quadrant of self
    (if (>= xCord 0)
        (if (>= yCord 0) 1 2)
        (if (< yCord 0) 3 4)))
)

(define mkPoint (x y)
   (initPoint (new Point) x y))
