5.3.3.8

15 Overriding

Is the test really on the 22nd? -- yes.

 

Inheritance and overriding

 

  Why do we use inheritance?

    1. Abstracting common code

    2. Managing the type system (in other languages)

    3. Extend existing system -- often overused, but very useful

 

  Example: points

    color-point% extends point%

      Use overriding to implement mv correctly for color-point%

    color-point% contains point%

      1. Class relationships aren't explicit

      2. Must manually delegate every inherited behavior

 

  Use mutation?

  Use update methods?

  Use copying + mutation?

    Performance analysis is hard and is best done empirically

 

  Dispatch

    Call the method most specific to the _object_

    e.g. double-move calls mv which dispatches to the appropriate method body

 

  Example: worlds

    big-bang expects many behaviors that we usually don't want to specify

 

  super to dispatch one level up

    Jumping >1 level would very often be a bad idea and break modularity

 

  With inheritance, data definitions are always _open_

    e.g. A Point is one of

          - (point% Num Num)

          - (color-point% Color Num Num)

          - ...

 

  Overriding lets you parametrize behavior of methods by supplying new behavior

    Powerful, just like higher-order functions in FP

    But power comes with responsibility: must respect behavioral subtyping!

Overriding in Java:

class Point {

    Integer x;

    Integer y;

 

    public Point(Integer x, Integer y) {

        this.x = x;

        this.y = y;

    }

 

    public Point mv(Integer dx, Integer dy) {

        return new Point(this.x + dx, this.y + dy);

    }

 

    public Point double_move(Integer dxy) {

        return this.mv(dxy,dxy);

    }

 

}

 

class CPoint extends Point {

    String color;

 

    public CPoint(String color, Integer x, Integer y) {

        super(x,y);

        this.color = color;

    }

 

    public CPoint mv(Integer dx, Integer dy) {

        return new CPoint(this.color, this.x-dx, this.y-dy);

    }

 

}

 

Overriding in class/4:

#lang class/4
 
;; A Point is (point% Number Number)
;; and implements
;; mv : Number Number -> Point
;; moves the point by this much in each direction
;; double-move : Number -> Point
;; move both x and y by the given amount
(define-class point%
  (fields x y)
  (define (mv dx dy)
    (point% (+ dx (send this x))
            (+ dy (send this y))))
  (define (double-move dxy)
    (mv dxy dxy))
 
  (check-expect (send (point% 1 2) mv 3 3) (point% 4 5))
  (check-expect (send (point% 1 2) double-move 3) (point% 4 5))
  )
 
(define-class color-point%
  (super point%)
  (fields color)
  (define (mv dx dy)
    (color-point% (send this color)
                  (+ dx (send this x))
                  (+ dy (send this y)))))
 
(check-expect (send (color-point% "red" 1 2) mv 2 2)
              (color-point% "red" 3 4))

Delegation in class/4:

#lang racket
 
 
 
;; A Point is (point% Number Number)
;; and implements
;; mv : Number Number -> Point
;; moves the point by this much in each direction
(define-class point%
  (fields x y)
  (define (mv dx dy)
    (point% (+ dx (send this x))
            (+ dy (send this y))))
  (check-expect (send (point% 1 2) mv 3 3) (point% 4 5))
  )
 
(define-class color-point
  (fields color pt)
  (define (mv dx dy)
    (color-point% (send this color)
                  (send (send this pt) mv dx dy))))

A default World:

#lang class/4
(require class/universe 2htdp/image)
 
;; A DWorld is (default-world%)
;; and implements
;; on-tick : DWorld -> DWorld
;; to-draw : DWorld -> Scene
;; ...
(define-class default-world%
  (define (on-tick)
    this)
  (define (to-draw)
    (empty-scene 300 300
                 )
    )
  )
 
(define-class circle-world%
  (super default-world%)
  (define (to-draw)
    (overlay (circle 20 "solid" "red")
             (empty-scene 300 300))))
 
(big-bang (circle-world%))