diff --git a/ClassMaterials/Module11/complex.java b/ClassMaterials/Module11/complex.java new file mode 100644 index 0000000..8193139 --- /dev/null +++ b/ClassMaterials/Module11/complex.java @@ -0,0 +1,129 @@ +// more complicated examples of inheritance and fields + +interface I { + int f (); + int g (); + int h (); +} + +class A implements I { + int i = 15; + int j = 20; + + A () { + System.out.println("calling constructor for A"); + show("i", i); show("j", j); + } + + // EFFECT: increments i + // RETURNS: the new value of i + j + + public int f () { + System.out.println("calling method f of class A"); + i = i + 1; + return (i + j); + } + + // RETURNS: mystery!! + + public int g () { + System.out.println("calling method g of class A"); + return (this.f() + 1); + } + + public int h () { + System.out.println("calling method g of class A"); + j = j + 10; + return (i - j); + } + + public void show (String str, int n) { + System.out.println(str + "=" + n); + } + + +} + +class B extends A implements I { + int k = 200; + + B () { + System.out.println("calling constructor for B"); + j = 100; + int n = this.h(); + show("i", i); show("j", j); show("k", k); + } + + public int g () { + System.out.println("calling method g of class B"); + return (i + j + k); + } + + public int h () { + System.out.println("calling method h of class B"); + j = j + 100; + return (super.g() + 30); + } + +} + + +class C extends B implements I { + + C () { + System.out.println("calling constructor for C"); + show("i", i); show("j", j); show("k", k); + } + + public int f () { + System.out.println("calling method f of class C"); + return (j - k); + } + + public int g () { + System.out.println("calling method g of class C"); + return (super.h() + 20); + } + + public int h () { + System.out.println("calling method h of class C"); + k = k + 20; + return (j + k); + } +} +class Tests { + + public static void main (String[] args) { + + System.out.println("***Starting tests for class A***"); + + I a1 = new A(); + + show("a1.f()", a1.f()); + show("a1.g()", a1.g()); + show("a1.h()", a1.h()); + + System.out.println("\n***Starting tests for class B***"); + + I b1 = new B(); + + show("b1.f()", b1.f()); + show("b1.g()", b1.g()); + show("b1.h()", b1.h()); + + System.out.println("\n***Starting tests for class C***"); + + I c1 = new C(); + + show("c1.f()", c1.f()); + show("c1.g()", c1.g()); + show("c1.h()", c1.h()); + + + } + + public static void show (String str, int n) { + System.out.println(str + "=" + n + "\n"); + } + +} diff --git a/ClassMaterials/Module11/module11.zip b/ClassMaterials/Module11/module11.zip new file mode 100644 index 0000000..4821474 Binary files /dev/null and b/ClassMaterials/Module11/module11.zip differ diff --git a/ClassMaterials/Module11/simple.java b/ClassMaterials/Module11/simple.java new file mode 100644 index 0000000..7040627 --- /dev/null +++ b/ClassMaterials/Module11/simple.java @@ -0,0 +1,129 @@ +// simple example of inheritance of methods and fields + +interface I { + + // no purpose; these are just for illustration + int f (); + int g (); + int g1 (); + int h (); +} + +class A implements I { + int i; + int j; + + A () { + System.out.println("calling constructor for A"); + this.i = 15; + this.j = 20; + System.out.println("i = " + i + " j = " + j); + System.out.println(""); + } + + public int f () { + System.out.println("calling method f of class A"); + return (i + j); + } + + public int g () { + System.out.println("calling method g of class A"); + return (i + this.f()); + } + + public int g1 () { + System.out.println("calling method g1 of class A"); + return (i + f()); + } + + public int h () { + System.out.println("calling method h of class A"); + return (i - j); + } +} + +class B extends A implements I { + int k; + + B () { + System.out.println("calling constructor for B"); + k = 200; + System.out.println("i = " + i + " j = " + j + " k = " + k); + System.out.println(""); + } + + public int f (){ + return 1000; + } + + public int h () { + System.out.println("calling method h of class B"); + return (30 + super.g()); + } +} + +class C extends B implements I { + + C () { + System.out.println("calling constructor for C"); + j = 100; + } + + public int f () { + return (j - k); + } + + public int g () { + return (super.h() + 20); + } + + public int h () { + return (j + k); + } +} + +class Tests { + + public static void main (String[] args) { + + System.out.println("***Starting tests for class A***"); + + I a1 = new A(); + + show("a1.f()", a1.f()); + show("a1.g()", a1.g()); + show("a1.g1()", a1.g1()); + show("a1.h()", a1.h()); + + System.out.println("\n***Starting tests for class B***"); + + I b1 = new B(); + + show("b1.f()", b1.f()); + show("b1.g()", b1.g()); + show("b1.g1()", b1.g1()); + show("b1.h()", b1.h()); + + System.out.println("\n***Starting tests for class C***"); + + I c1 = new C(); + + show("c1.f()", c1.f()); + show("c1.g()", c1.g()); + show("c1.g1()", c1.g1()); + show("c1.h()", c1.h()); + + + } + + static void show (String str, int n) { + System.out.println(str + "=" + n + "\n"); + } + +} + + + + + + diff --git a/CourseMaps/module10.jpg b/CourseMaps/module10.jpg index f1de4e8..72c56e0 100644 Binary files a/CourseMaps/module10.jpg and b/CourseMaps/module10.jpg differ diff --git a/CourseMaps/module11.jpg b/CourseMaps/module11.jpg index 5b1e542..7de5016 100644 Binary files a/CourseMaps/module11.jpg and b/CourseMaps/module11.jpg differ diff --git a/CourseMaps/module12.jpg b/CourseMaps/module12.jpg index 9755504..63f551d 100644 Binary files a/CourseMaps/module12.jpg and b/CourseMaps/module12.jpg differ diff --git a/Efficiency2/ackermann3.html b/Efficiency2/ackermann3.html index 64c4728..665bc9d 100644 --- a/Efficiency2/ackermann3.html +++ b/Efficiency2/ackermann3.html @@ -9,7 +9,7 @@ - Ackermann's Function in ps11 + Ackermann's Function in a small hypothetical language Ackermann's Function in ps11 -
+
+

ps11 was a small language that was used as an example in CS 5010 in + Spring 2017. As you will see in an upcoming slide, it had an +interpreter and two compilers. +

+
       ack (m, n)
         if m = 0
diff --git a/Efficiency2/gcPSZero.html b/Efficiency2/gcPSZero.html
index b497f16..5245063 100644
--- a/Efficiency2/gcPSZero.html
+++ b/Efficiency2/gcPSZero.html
@@ -33,7 +33,7 @@ 

need a more typical benchmark.

- The flight-scheduling problem posed by Problem Set 00, + The flight-scheduling problem posed as Problem Set 00 in Spring 2017, at the beginning of the semester, gives us a more typical benchmark. Because this is not a course on algorithms, diff --git a/Efficiency2/gcSpecialPleading.html b/Efficiency2/gcSpecialPleading.html index 4402cb6..623cae0 100644 --- a/Efficiency2/gcSpecialPleading.html +++ b/Efficiency2/gcSpecialPleading.html @@ -43,7 +43,7 @@

Many programmers take pride in their knowledge and skillful use of the programming language they know best. When confronted with empirical evidence showing their - favorite language do not always perform as well as + favorite language does not always perform as well as other languages, they may become defensive and resort to special pleading.

diff --git a/Examples/09-1-UTCv1/UTC.java b/Examples/09-1-UTC/UTC.java similarity index 100% rename from Examples/09-1-UTCv1/UTC.java rename to Examples/09-1-UTC/UTC.java diff --git a/Examples/09-1-UTCv1/UTC1.java b/Examples/09-1-UTC/UTC1.java similarity index 100% rename from Examples/09-1-UTCv1/UTC1.java rename to Examples/09-1-UTC/UTC1.java diff --git a/Examples/09-1-UTCv1/UTC2.java b/Examples/09-1-UTC/UTC2.java similarity index 100% rename from Examples/09-1-UTCv1/UTC2.java rename to Examples/09-1-UTC/UTC2.java diff --git a/Examples/09-1-UTCv1/UTCs.java b/Examples/09-1-UTC/UTCs.java similarity index 100% rename from Examples/09-1-UTCv1/UTCs.java rename to Examples/09-1-UTC/UTCs.java diff --git a/Examples/09-1-basics.rkt b/Examples/09-1-basics.rkt deleted file mode 100644 index 25293e6..0000000 --- a/Examples/09-1-basics.rkt +++ /dev/null @@ -1,105 +0,0 @@ -#lang racket - -(require "extras.rkt") -(require rackunit) - -;; examples from Lesson 9.1 - -(define Interface1<%> - (interface () - foo ; -> Int - bar ; Int -> Int - baz ; Int -> Int - )) - - - -(define Class1% - (class* object% (Interface1<%>) - - (init-field x y r) ;; x,y,r : Int - - (super-new) ;; required magic - - ;; foo : -> Int - (define/public (foo) (+ x y)) - - ;; bar : Int -> Int - (define/public (bar n) (+ r n)) - - ;; baz : Int -> Int - (define/public (baz n) - (+ (send this foo) n)) - - )) - -(define Class2% - (class* object% (Interface1<%>) - - (init-field a b c) ; a, b, c : Int - - (super-new) - - ;; foo : -> Int - (define/public (foo) (+ a b)) - - ;; bar : Int -> Int - (define/public (bar n) (* c n)) - - ;; baz : Int -> Int - (define/public (baz n) - (+ (send this foo) n)) - - )) - -(define Class2a% - (class* object% (Interface1<%>) - - (init-field a b c) ; a, b, c : Int - - (field [a1 (- a)]) ; add a new field, initialized to -a - - (super-new) - - ;; foo : -> Int - ; (define/public (foo) (+ a b)) - (define/public (foo) (- b a1)) - - ;; bar : Int -> Int - (define/public (bar n) (* c n)) - - ;; baz : Int -> Int - (define/public (baz n) - (+ (send this foo) n)) - - )) - - - -(define obj1 (new Class1% [x 10][y 20][r 10])) -(define obj2 (new Class1% [x 15][y 35][r 5])) -(define obj3 (new Class2% [a 15][b 35][c 5])) -(define obj3a (new Class2a% [a 15][b 35][c 5])) - -(begin-for-test - - (check-equal? (send obj1 foo) 30) - (check-equal? (send obj2 foo) 50) - - (check-equal? (send obj1 bar 8) 18) - (check-equal? (send obj2 bar 8) 13) - - (check-equal? (send obj1 baz 20) 50) - (check-equal? (send obj2 baz 20) 70) - - (check-equal? (send obj2 bar 8) 13) - (check-equal? (send obj3 bar 8) 40) - - ;; foo is the only method that is different in Class2% and Class2a%. - (check-equal? (send obj3 foo) (send obj3a foo)) - - - ) - - - diff --git a/Examples/09-2-1-space-invaders-1.rkt b/Examples/09-2-1-space-invaders-1.rkt deleted file mode 100644 index 94f6b9f..0000000 --- a/Examples/09-2-1-space-invaders-1.rkt +++ /dev/null @@ -1,432 +0,0 @@ -#lang racket - -;; space-invaders-1.rkt - -;; the world will consist of a list of Widget<%>'s, and a tick -;; counter to indicate the current time. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; start with (run framerate). Typically: (run 0.25) - -;; Press "b" to drop a new bomb. -;; Bombs fall at a constant rate. - -;; Helicopter rises at a constant rate. -;; the helicopter is smoothly draggable - -;; there is no interaction between the helicopter and the bombs. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - -;;; CONSTANTS - -(define CANVAS-WIDTH 200) -(define CANVAS-HEIGHT 400) - -(define EMPTY-CANVAS (empty-scene 200 400)) - -;; some arbitrary choices -(define BOMB-INITIAL-X 75) -(define BOMB-INITIAL-Y 0) -(define BOMB-INITIAL-RADIUS 10) - -(define HELI-INITIAL-X 100) -(define HELI-INITIAL-Y 300) - -(define NEW-BOMB-EVENT "b") -(define NEW-HELI-EVENT "h") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Data Definitions - -;; A Time is a NonNegative Integer - -;; A Widget is an object whose class implements the Widget<%> -;; interface. - -(define-struct world (widgets time)) - -;; A World is a (make-world ListOfWidget Time) -;; INTERP: (make-world lst t) represents a world containing the -;; widgets in lst at time t (in ticks). - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACEs - -;; Every object that lives in the world must implement the Widget<%> -;; interface. - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; initial-world : -> World -;; RETURNS: a world with a helicopter and no bombs -(define (initial-world) - (make-world - (list (new-heli)) - 0)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the final state of the world -(define (run rate) - (big-bang (initial-world) - (on-tick world-after-tick rate) - (on-draw world-to-scene) - (on-key world-after-key-event) - (on-mouse world-after-mouse-event))) - -;; GP: Let's say the world should launch a new helicopter every 10 -;; ticks. How could we accomplish that? - -;; world-after-tick : World -> World -;; Use HOFC map on the Widget's in w -(define (world-after-tick w) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-tick)) - objs) - (+ 1 t)))) - -;; world-to-scene : World -> Scene -;; Use HOFC foldr on the Widgets in w -(define (world-to-scene w) - (foldr - ;; Widget Scene -> Scene - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (world-widgets w))) - - -;; world-after-key-event : World KeyEvent -> World -;; STRATEGY: Cases on kev -;; "b" creates a new bomb -;; "h" creates a new heli -;; other keystrokes are passed on to the widgets in the world. - -(define (world-after-key-event w kev) - (let ((objs (world-widgets w)) - (t (world-time w))) - (cond - [(key=? kev NEW-BOMB-EVENT) - (make-world - (cons (new-bomb t) objs) - t)] - [(key=? kev NEW-HELI-EVENT) - (make-world - (cons (new-heli) objs) - t)] - [else - (make-world - (map - (lambda (obj) (send obj after-key-event kev)) - (world-widgets w)) - t)]))) - -;; world-after-mouse-event : World Nat Nat MouseEvent -> World -;; STRATGY: Cases on mev -(define (world-after-mouse-event w mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down w mx my)] - [(mouse=? mev "drag") - (world-after-drag w mx my)] - [(mouse=? mev "button-up") - (world-after-button-up w mx my)] - [else w])) - -; World Nat Nat -> World -; STRATEGY: Use HOF map on the widgets in w -(define (world-after-button-down w mx my) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-button-down mx my)) - objs) - t))) - - -(define (world-after-button-up w mx my) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-button-up mx my)) - objs) - t))) - -(define (world-after-drag w mx my) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-drag mx my)) - objs) - t))) - -;; Challenge question: Could these 3 functions be generalized? - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Here's what a class definition looks like: - -;; classes are like data definitions. They should have a purpose statement -;; describing what information they are supposed to represent, and -;; interpretations of the fields describing the meaning of each piece of data. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; We have two classes that implement Widget<%>: Heli% and Bomb% - -;; Helicopters start near the bottom of the screen and rise slowly. -;; They are selectable and draggable. - -;; Constructor template for Heli%: -;; (new Heli% [x Integer][y Integer] -;; [selected? Boolean][mx Integer][my Integer]) -;; the last 3 arguments are optional -;; Interpretation: An object of class Heli% represents a helicopter. - -(define Heli% - (class* object% (Widget<%>) - - ;; the init-fields are the values that may vary from one helicopter to - ;; the next. - - ; the x and y position of the center of the helicopter - (init-field x y) - - ; is the helicopter selected? Default is false. - (init-field [selected? false]) - - ;; if the helicopter is selected, the position of - ;; the last button-down event inside the helicopter, relative to the - ;; helicopter's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ; the helicopter's radius - (field [r 15]) - - ; image for displaying the helicopter - (field [HELI-IMG (circle r "outline" "blue")]) - ; the helicopter's speed, in pixels/tick - (field [HELISPEED -4]) - - (super-new) - - ;; after-tick : -> Widget - ;; RETURNS: A helicopter like this one, but as it should be after a tick - ;; a selected helicopter doesn't move. - ;; STRATEGY: Cases on selected? - (define/public (after-tick) - (if selected? - this - (new Heli% - [x x] - [y (+ y HELISPEED)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my]))) - - ;; after-key-event : KeyEvent -> Widget - ;; RETURNS: A helicopter like this one, but as it should be after the - ;; given key event. - ;; DETAILS: a helicopter ignores key events - (define/public (after-key-event kev) - this) - - ; after-button-down : Integer Integer -> Widget - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in the helicopter - (define/public (after-button-down mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)]) - this)) - - ; after-button-up : Integer Integer -> Widget - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in the helicopter. - ; If the helicopter is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? false] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - ; after-drag : Integer Integer -> Widget - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the helicopter is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Heli% - [x (- mx saved-mx)] - [y (- my saved-my)] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this helicopter painted - ;; on it. - (define/public (add-to-scene scene) - (place-image HELI-IMG x y scene)) - - ;; in-heli? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this helicopter. - (define (in-heli? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr r))) - - ;; test methods, to probe the helicopter state. Note that we don't have - ;; a probe for radius. - ;; -> Int - (define/public (for-test:x) x) - ;; -> Int - (define/public (for-test:y) y) - ;; -> Boolean - (define/public (for-test:selected?) selected?) - - ;; -> (list Int Int Boolean) - (define/public (for-test:heli-state) (list x y selected?)) - - )) - -;; make-heli: -> Widget -;; GIVEN: no arguments -;; RETURNS: a new object of class Heli% near the bottom of the screen. - -;; NOTE: the contract says Widget, because our contracts are ALWAYS in -;; terms of interfaces (remember, a Widget is an object that -;; implements Widget<%>). The purpose statement gives the additional -;; information that the Widget returned by make-heli happens to be an -;; object of class Heli%. - -(define (new-heli) - (new Heli% [x HELI-INITIAL-X][y HELI-INITIAL-Y])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Bombs start near the top of the screen. They just fall. - -;; Constructor template for Bomb%: -;; (new Bomb% [x Integer][y Integer]) -;; Interpretation: An object of class Bomb% represents a bomb. - -;; make-bomb : Time -> Widget -;; GIVEN: A time t -;; RETURNS: a new object of class Bomb% near the top of the screen. -;; The time argument is ignored. - -;; SEE NOTE ABOVE ABOUT THIS CONTRACT - -(define (new-bomb t) - (new Bomb% [x BOMB-INITIAL-X][y BOMB-INITIAL-Y])) - -(define Bomb% - - (class* object% (Widget<%>) - (init-field x y) ; the bomb's x and y position - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ;; image for displaying the bomb - (field [BOMB-IMG (circle 10 "solid" "red")]) - ; the bomb's speed, in pixels/tick - (field [BOMB-SPEED 8]) - - (super-new) - - ;; after-tick : -> Widget - ;; RETURNS: A bomb like this one, but as it should be after a tick - ;; DETAILS: the bomb moves vertically by BOMB-SPEED - (define/public (after-tick) - (new Bomb% [x x][y (+ y BOMB-SPEED)])) - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this bomb painted - ;; on it. - (define/public (add-to-scene scene) - (place-image BOMB-IMG x y scene)) - - ;; the bomb doesn't have any other behaviors - (define/public (after-button-down mx my) this) - (define/public (after-drag mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-key-event kev) this) - - ;; test methods, to probe the bomb state. - (define/public (for-test:x) x) - (define/public (for-test:y) y) - - )) - - - - - - - - diff --git a/Examples/09-2-2-space-invaders-2.rkt b/Examples/09-2-2-space-invaders-2.rkt deleted file mode 100644 index 9cb1ed5..0000000 --- a/Examples/09-2-2-space-invaders-2.rkt +++ /dev/null @@ -1,472 +0,0 @@ -#lang racket - -;; space-invaders-2.rkt - -;; just like space-invaders-1, but in this version, the world will be an object - -;; the world will consist of a list of Widget<%>'s, and a tick -;; counter to indicate the current time. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; start with (run framerate). Typically: (run 0.25) - -;; Press "b" to drop a new bomb. -;; Bombs fall at a constant rate. - -;; Press "h" to start a new helicopter -;; Helicopter rises at a constant rate. -;; the helicopter is smoothly draggable - -;; there is no interaction between the helicopter and the bombs. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - -;;; CONSTANTS - -(define CANVAS-WIDTH 200) -(define CANVAS-HEIGHT 400) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - -;; some arbitrary choices -(define BOMB-INITIAL-X 75) -(define BOMB-INITIAL-Y 0) -(define BOMB-INITIAL-RADIUS 10) - -(define HELI-INITIAL-X 100) -(define HELI-INITIAL-Y 300) - -(define NEW-BOMB-EVENT "b") -(define NEW-HELI-EVENT "h") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Data Definitions - -;; A Time is a NonNegative Integer - -;; A Widget is an object whose class implements the Widget<%> -;; interface. - -;; A World is an object whose class implements the World<%> -;; interface. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; big-bang will communicate with the world through the World<%> -;; interface. - -(define World<%> - (interface () - - ; -> World - ; GIVEN: no arguments - ; RETURNS: the state of the world at the next tick - after-tick - - ; Integer Integer MouseEvent-> World - ; GIVEN: a location - ; RETURNS: the state of the world that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> World - ; GIVEN: a key event - ; RETURNS: the state of the world that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - )) - - -;; Every object that lives in the world must implement the Widget<%> -;; interface. - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a helicopter and no bombs -(define (initial-world) - (make-world - (list (new-heli)) - 0)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the final state of the world -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (send w after-tick)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (send w after-key-event kev))) - (on-mouse - (lambda (w mx my mev) - (send w after-mouse-event mx my mev))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The World% class - -;; We will have only one class that implements World<%>: World% - -;; Constructor template for World%: -;; (new World% [objs ListOfWidget][t Time]) -;; Interpretation: An object of class World% takes signals from -;; big-bang and distributes them to its objects as appropriate. - - -;; make-world : ListOfWidget Time -> World -;; GIVEN: a list of widgets and a time -;; RETURNS: an object of class World% containing the given list of -;; widgets and time. -(define (make-world objs t) - (new World% [objs objs][t t])) - -(define World% - (class* object% (World<%>) - - (init-field objs) ; ListOfWidget - (init-field t) ; Time - - (super-new) - - ;; after-tick : -> World - ;; Use HOFC map on the Widget's in this World - - (define/public (after-tick) - (make-world - (map - (lambda (obj) (send obj after-tick)) - objs) - (+ 1 t))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets in this World - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - objs)) - - - ;; after-key-event : KeyEvent -> World - ;; STRATEGY: Cases on kev - ;; "b" and "h" create new bomb and new helicopter; - ;; other keystrokes are passed on to the objects in the world. - - (define/public (after-key-event kev) - (cond - [(key=? kev NEW-BOMB-EVENT) - (make-world - (cons (new-bomb t) objs) - t)] - [(key=? kev NEW-HELI-EVENT) - (make-world - (cons (new-heli) objs) - t)] - [else - (make-world - (map - (lambda (obj) (send obj after-key-event kev)) - objs) - t)])) - - ;; after-mouse-event : Nat Nat MouseEvent -> World - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (make-world - (map - (lambda (obj) (send obj after-button-down mx my)) - objs) - t)) - - - (define (world-after-button-up mx my) - (make-world - (map - (lambda (obj) (send obj after-button-up mx my)) - objs) - t)) - - (define (world-after-drag mx my) - (make-world - (map - (lambda (obj) (send obj after-drag mx my)) - objs) - t)) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; We have two classes of Widgets: Helicopters and Bombs - -;; Helicopters start near the bottom of the screen and rise slowly. -;; They are selectable and draggable. - -;; Constructor template for Heli%: -;; (new Heli% [x Integer][y Integer] -;; [selected? Boolean][mx Integer][my Integer]) -;; the last 3 arguments are optional -;; Interpretation: An object of class Heli% represents a helicopter. - - -;; unchanged from 09-2-1. -(define Heli% - (class* object% (Widget<%>) - - ;; the init-fields are the values that may vary from one helicopter to - ;; the next. - - ; the x and y position of the center of the helicopter - (init-field x y) - - ; is the helicopter selected? Default is false. - (init-field [selected? false]) - - ;; if the helicopter is selected, the position of - ;; the last button-down event inside the helicopter, relative to the - ;; helicopter's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ; the helicopter's radius - (field [r 15]) - - ; image for displaying the helicopter - (field [HELI-IMG (circle r "outline" "blue")]) - ; the helicopter's speed, in pixels/tick - (field [HELISPEED -4]) - - (super-new) - - ;; after-tick : Time -> Widget - ;; RETURNS: A helicopter like this one, but as it should be after a tick - ;; a selected helicopter doesn't move. - ;; STRATEGY: Cases on selected? - (define/public (after-tick) - (if selected? - this - (new Heli% - [x x] - [y (+ y HELISPEED)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my]))) - - ;; after-key-event : KeyEvent -> Widget - ;; RETURNS: A world like this one, but as it should be after the - ;; given key event. - ;; DETAILS: a helicopter ignores key events - (define/public (after-key-event kev) - this) - - ; after-button-down : Integer Integer -> Widget - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in the helicopter - (define/public (after-button-down mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)]) - this)) - - ; after-button-up : Integer Integer -> Widget - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in the helicopter. - ; If the helicopter is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? false] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - ; after-drag : Integer Integer -> Widget - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the helicopter is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Heli% - [x (- mx saved-mx)] - [y (- my saved-my)] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this helicopter painted - ;; on it. - (define/public (add-to-scene scene) - (place-image HELI-IMG x y scene)) - - ;; in-heli? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this helicopter. - (define (in-heli? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr r))) - - ;; test methods, to probe the helicopter state. Note that we don't have - ;; a probe for radius. - ;; -> Int - (define/public (for-test:x) x) - ;; -> Int - (define/public (for-test:y) y) - ;; -> Boolean - (define/public (for-test:selected?) selected?) - - ;; -> (list Int Int Boolean) - (define/public (for-test:heli-state) (list x y selected?)) - - )) - -;; make-heli: -> Widget -;; GIVEN: no arguments -;; RETURNS: a new object of class Heli% near the bottom of the screen. - -;; NOTE: the contract says Widget, because our contracts are ALWAYS in -;; terms of interfaces (remember, a Widget is an object that -;; implements Widget<%>). The purpose statement gives the additional -;; information that the Widget returned by make-heli happens to be an -;; object of class Heli%. - -(define (new-heli) - (new Heli% [x HELI-INITIAL-X][y HELI-INITIAL-Y])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Bombs start near the top of the screen. They just fall. - -;; Constructor template for Bomb%: -;; (new Bomb% [x Integer][y Integer]) -;; Interpretation: An object of class Bomb% represents a bomb. - -;; make-bomb : Time -> Widget -;; GIVEN: A time t -;; RETURNS: a new object of class Bomb% near the top of the screen. -;; The time argument is ignored. - -;; SEE NOTE ABOVE ABOUT THIS CONTRACT - -(define (new-bomb t) - (new Bomb% [x BOMB-INITIAL-X][y BOMB-INITIAL-Y])) - -(define Bomb% - (class* object% (Widget<%>) - (init-field x y) ; the bomb's x and y position - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ;; image for displaying the bomb - (field [BOMB-IMG (circle 10 "solid" "red")]) - ; the bomb's speed, in pixels/tick - (field [BOMB-SPEED 8]) - - (super-new) - - ;; after-tick : -> Widget - ;; RETURNS: A bomb like this one, but as it should be after a tick - ;; DETAILS: the bombcopter moves vertically by BOMB-SPEED - (define/public (after-tick) - (new Bomb% [x x][y (+ y BOMB-SPEED)])) - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this bomb painted - ;; on it. - (define/public (add-to-scene scene) - (place-image BOMB-IMG x y scene)) - - ;; the bomb doesn't have any other behaviors - (define/public (after-button-down mx my) this) - (define/public (after-drag mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-key-event kev) this) - - ;; test methods, to probe the bomb state. - (define/public (for-test:x) x) - (define/public (for-test:y) y) - - )) - - - - diff --git a/Examples/09-2-AList-v1/AList.java b/Examples/09-2-AList-v1/AList.java new file mode 100644 index 0000000..c2ac4c4 --- /dev/null +++ b/Examples/09-2-AList-v1/AList.java @@ -0,0 +1,21 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +interface AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/09-2-AList-v1/AList1.java b/Examples/09-2-AList-v1/AList1.java new file mode 100644 index 0000000..a16c9c9 --- /dev/null +++ b/Examples/09-2-AList-v1/AList1.java @@ -0,0 +1,73 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } +} + +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + if (key.equals (this.key)) + return true; + else + return rest.contains (key); + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + +} diff --git a/Examples/09-2-AList-v1/AListTests.java b/Examples/09-2-AList-v1/AListTests.java new file mode 100644 index 0000000..9a25392 --- /dev/null +++ b/Examples/09-2-AList-v1/AListTests.java @@ -0,0 +1,86 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class AListTests { + + public static void main (String[] args) { + AList a0 = new EmptyAList(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkFalse (a0.contains ("x")); + checkTrue (a3.contains ("z")); + checkTrue (a4.contains ("x")); + checkFalse (a4.contains ("b")); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + checkTrue (b2.lookup ("x") == 1); + checkTrue (b2.lookup ("y") == 2); + checkTrue (b4.lookup ("x") == 33); + checkTrue (b4.lookup ("y") == 44); + checkTrue (b4.lookup ("b") == 22); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) + testsPassed = testsPassed + 1; + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (testsFailed > 0) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/09-2-UTCv2/UTC.java b/Examples/09-2-UTCv2/UTC.java deleted file mode 100644 index a614ee9..0000000 --- a/Examples/09-2-UTCv2/UTC.java +++ /dev/null @@ -1,18 +0,0 @@ -// A UTC is an object of any class that implements UTC. -// -// Interpretation: A UTC represents a Universal Coordinated Time. - -interface UTC { - - // Returns the hour, between 0 and 23 inclusive. - - int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - boolean isEqual (UTC t2); -} diff --git a/Examples/09-2-UTCv2/UTC1.java b/Examples/09-2-UTCv2/UTC1.java deleted file mode 100644 index df3be8a..0000000 --- a/Examples/09-2-UTCv2/UTC1.java +++ /dev/null @@ -1,80 +0,0 @@ -// Constructor template for UTC1: -// new UTC1 (h, m) -// Interpretation: -// h is the hour (between 0 and 23, inclusive) -// m is the minute (between 0 and 59, inclusive) - -class UTC1 implements UTC { - - int h; // the hour, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC1 (int h, int m) { - this.h = h; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { return h; } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return UTCs.isEqual (this, t2); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return UTCs.hashCode (this); - } - - public String toString () { - return UTCs.toString (this); - } - - // a main method for unit testing - - public static void main (String[] args) { - UTC1tests.main(args); - } -} - -// Unit tests for UTC1. - -class UTC1tests { - - public static void main (String[] args) { - UTC t1 = new UTC1 (15, 31); - UTC t2 = new UTC1 (14, 31); - UTC t3 = new UTC1 (15, 32); - UTC t4 = new UTC1 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC1 passed."); - } -} diff --git a/Examples/09-2-UTCv2/UTC2.java b/Examples/09-2-UTCv2/UTC2.java deleted file mode 100644 index d0afb41..0000000 --- a/Examples/09-2-UTCv2/UTC2.java +++ /dev/null @@ -1,88 +0,0 @@ -// Constructor template for UTC2: -// new UTC2 (h, m) -// Interpretation: -// h is the UTC hour (between 0 and 23, inclusive) -// m is the UTC minute (between 0 and 59, inclusive) -// Representation: -// Internally, the hour is represented in Eastern Standard Time, -// which is five hours behind UTC. - -class UTC2 implements UTC { - - int h; // the hour in EST, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC2 (int h, int m) { - this.h = (h >= 5) ? (h - 5) : h + 19; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { - if (h < 19) - return h + 5; - else - return h - 19; - } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return UTCs.isEqual (this, t2); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return UTCs.hashCode (this); - } - - public String toString () { - return UTCs.toString (this); - } - - // a main method for unit testing - - public static void main (String[] args) { - UTC2tests.main(args); - } -} - -// Unit tests for UTC2. - -class UTC2tests { - - public static void main (String[] args) { - UTC t1 = new UTC2 (15, 31); - UTC t2 = new UTC2 (14, 31); - UTC t3 = new UTC2 (15, 32); - UTC t4 = new UTC2 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC2 passed."); - } -} \ No newline at end of file diff --git a/Examples/09-2-UTCv2/UTCs.java b/Examples/09-2-UTCv2/UTCs.java deleted file mode 100644 index 30660ae..0000000 --- a/Examples/09-2-UTCv2/UTCs.java +++ /dev/null @@ -1,145 +0,0 @@ -// In Java, it is often convenient to define static methods -// that deal with some interface type in a separate class -// that does not itself implement the interface. -// -// By convention, the name of that class is the plural of the -// name of the interface. -// -// For example: Collections is a class that defines static methods -// for the Collection type. - -import java.util.Random; - -// The UTCs class defines static methods for the UTC type. -// In particular, it defines a static factory method for creating -// values of the UTC type. - -public class UTCs { - - // Dynamic isEqual methods should delegate to this static method. - - public static boolean isEqual (UTC t1, UTC t2) { - return (t1.hour() == t2.hour()) && (t1.minute() == t2.minute()); - } - - // Dynamic hashCode methods should delegate to this static method. - - public static int hashCode (UTC t) { - return 100 * t.hour() + t.minute(); - } - - // Dynamic toString methods should delegate to this static method. - - public static String toString (UTC t) { - return ((Integer) (100 * t.hour() + t.minute())).toString(); - } - - // random number generator, to be used as a coin flip - - private static Random coinFlips = new Random(); - - // static factory method for creating a UTC - // GIVEN: the hour in [0,23] and the minute in [0,59] - // RETURNS: a UTC with that hour and minute - - public static UTC make (int h, int m) { - // flips a coin to decide whether to return an object - // of class UTC1 or UTC2 - - if (coinFlips.nextBoolean()) - return new UTC1 (h, m); - else - return new UTC2 (h, m); - } - - // main method for testing - - public static void main (String[] args) { - for (String arg : args) - System.out.println (arg); - UTCsTests.main (args); - } -} - -// Tests for UTC objects created by the static factory method in UTCs. - -class UTCsTests { - - public static void main (String[] args) { - - // We'll do these tests several times, to increase the - // probability that objects of different classes will be created. - - int NTESTS = 5; // how many times we'll run each test - - for (int i = 0; i < NTESTS; i = i + 1) { - UTC t0000 = UTCs.make (0, 0); // always test boundary cases - UTC t0059 = UTCs.make (0, 59); - UTC t2300 = UTCs.make (23, 0); - UTC t2359 = UTCs.make (23, 59); - UTC t1531 = UTCs.make (15, 31); // and test typical cases - - assert t0000.hour() == 0 : "wrong hour for t0000"; - assert t0000.minute() == 0 : "wrong minute for t0000"; - assert t0059.hour() == 0 : "wrong hour for t0059"; - assert t0059.minute() == 59 : "wrong minute for t0059"; - assert t2300.hour() == 23 : "wrong hour for t2300"; - assert t2300.minute() == 0 : "wrong minute for t2300"; - assert t2359.hour() == 23 : "wrong hour for t2359"; - assert t2359.minute() == 59 : "wrong minute for t2359"; - assert t1531.hour() == 15 : "wrong hour for t1531"; - assert t1531.minute() == 31 : "wrong minute for t1531"; - - assert t0000.isEqual(t0000) : "isEqual says t0000 != t0000"; - assert t0059.isEqual(t0059) : "isEqual says t0059 != t0059"; - assert t2300.isEqual(t2300) : "isEqual says t2300 != t2300"; - assert t2359.isEqual(t2359) : "isEqual says t2359 != t2359"; - assert t1531.isEqual(t1531) : "isEqual says t1531 != t1531"; - - assert t0000.isEqual(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.isEqual(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.isEqual(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.isEqual(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.isEqual(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.isEqual(t0059)) : "isEqual says t0000 = t0059"; - assert ! (t0059.isEqual(t2359)) : "isEqual says t0059 = t2359"; - assert ! (t2359.isEqual(t2300)) : "isEqual says t2359 = t2300"; - - // tests of the usual triumvirate - - assert t0000.equals(t0000) : "equals says t0000 != t0000"; - assert t0059.equals(t0059) : "equals says t0059 != t0059"; - assert t2300.equals(t2300) : "equals says t2300 != t2300"; - assert t2359.equals(t2359) : "equals says t2359 != t2359"; - assert t1531.equals(t1531) : "equals says t1531 != t1531"; - - assert t0000.equals(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.equals(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.equals(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.equals(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.equals(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.equals(t0059)) : "equals says t0000 = t0059"; - assert ! (t0059.equals(t2359)) : "equals says t0059 = t2359"; - assert ! (t2359.equals(t2300)) : "equals says t2359 = t2300"; - - assert ! (t0000.equals(null)) : "equals says t0000 = null"; - assert ! (t0059.equals("foo")) : "equals says t0059 = a string"; - - assert t0000.hashCode() == (UTCs.make(0, 0).hashCode()); - assert t0059.hashCode() == (UTCs.make(0, 59).hashCode()); - assert t2300.hashCode() == (UTCs.make(23, 0).hashCode()); - assert t2359.hashCode() == (UTCs.make(23, 59).hashCode()); - assert t1531.hashCode() == (UTCs.make(15, 31).hashCode()); - - assert t0000.toString().equals(UTCs.make(0, 0).toString()); - assert t0059.toString().equals(UTCs.make(0, 59).toString()); - assert t2300.toString().equals(UTCs.make(23, 0).toString()); - assert t2359.toString().equals(UTCs.make(23, 59).toString()); - assert t1531.toString().equals(UTCs.make(15, 31).toString()); - } - - System.out.println ("UTCs tests passed."); - } -} \ No newline at end of file diff --git a/Examples/09-3-1-shapes-functional.rkt b/Examples/09-3-1-shapes-functional.rkt deleted file mode 100644 index a310c6e..0000000 --- a/Examples/09-3-1-shapes-functional.rkt +++ /dev/null @@ -1,98 +0,0 @@ -#lang racket - -;; 09-3-shapes-functional.rkt - -(require rackunit) -(require "extras.rkt") -(require 2htdp/image) - -(define-struct my-circle (x y r color) #:transparent) -(define-struct my-square (x y l color) #:transparent) -(define-struct my-composite (front back) #:transparent) - -;; The #;transparent makes the fields of the structs visible for -;; printing and to equal? - -;; A Shape is one of -;; -- (make-my-circle Number Number Number ColorString) -;; -- (make-my-square Number Number Number ColorString) -;; -- (make-my-composite Shape Shape) - -;; interp: -;; (x,y) is position in pixels (of center of shape) -;; r is radius of circle in pixels -;; l is length of side of square, in pixels -;; c is color, expressed as a ColorString. -;; in my-composite, front is the shape in front, back is the shape in back. - -;; TEMPLATE -;; shape-fn : Shape -> ?? -#; -(define (shape-fn s) - (cond - [(my-circle? s) (... - (my-circle-x s) - (my-circle-y s) - (my-circle-r s) - (my-circle-color s))] - [(my-square? s) (... - (my-square-x s) - (my-square-y s) - (my-square-r s) - (my-square-color s))] - [(my-composite? s) (... - (shape-fn (my-composite-front s)) - (shape-fn (my-composite-back s)))])) - -;; weight : Shape -> Number -;; GIVEN: a shape -;; RETURNS: the weight of the shape, assuming that each shape weighs 1 -;; gram per pixel of area. -;; STRATEGY: Structural Decomposition on s : Shape -(define (weight s) - (cond - [(my-circle? s) (* pi (my-circle-r s) (my-circle-r s))] - [(my-square? s) (* (my-square-l s) (my-square-l s))] - [(my-composite? s) (+ (weight (my-composite-front s)) - (weight (my-composite-back s)))])) - -;; add-to-scene : Shape Scene -> Scene -;; RETURNS: a scene like the given one, but with the given shape -;; painted on it. -;; STRATEGY: Structural Decomposition on s : Shape -(define (add-to-scene s scene) - (cond - [(my-circle? s) - (local - ((define IMG (circle (my-circle-r s) "solid" (my-circle-color s)))) - (place-image IMG - (my-circle-x s) - (my-circle-y s) - scene))] - [(my-square? s) - (local - ((define IMG (square (my-square-l s) "solid" (my-square-color s)))) - (place-image IMG - (my-square-x s) - (my-square-y s) - scene))] - [(my-composite? s) - ;; paint the back image first, then the front image - (add-to-scene (my-composite-front s) - (add-to-scene (my-composite-back s) - scene))])) - -(define EMPTY-CANVAS (empty-scene 200 100)) - - -(define s1 (make-my-circle 50 20 40 "red")) -(define s2 (make-my-square 80 70 40 "blue")) -(define s3 (make-my-composite s1 s2)) - -(begin-for-test - (check-= (weight s1) (* pi 1600) .1) - (check-equal? (weight s2) 1600) - (check-= (weight s3) (+ (* pi 1600) 1600) .1)) - - - diff --git a/Examples/09-3-2-shapes-separate-functions.rkt b/Examples/09-3-2-shapes-separate-functions.rkt deleted file mode 100644 index eecc62e..0000000 --- a/Examples/09-3-2-shapes-separate-functions.rkt +++ /dev/null @@ -1,102 +0,0 @@ -#lang scheme - -;; 09-4-shapes-separate-functions.rkt - -;; this version uses separate functions for dispatch and operation - -(require rackunit) -(require "extras.rkt") -(require 2htdp/image) - -(define-struct my-circle (x y r color) #:transparent) -(define-struct my-square (x y l color) #:transparent) -(define-struct my-composite (front back) #:transparent) - -;; A Shape is one of -;; -- (make-my-circle Number Number Number ColorString) -;; -- (make-my-square Number Number Number ColorString) -;; -- (make-my-composite Shape Shape) - -;; interp: -;; (x,y) is position in pixels (of center for circle, of UL corner for square) -;; r is radius of circle in pixels -;; l is length of side of square, in pixels -;; c is color, expressed as a ColorString. -;; in my-composite, front is the shape in front, back is the shape in back. - -;; weight : Shape -> Number -;; GIVEN: a shape -;; RETURNS: the weight of the shape, assuming that each shape weighs 1 -;; gram per pixel of area. -;; STRATEGY: Use template for Shape -(define (weight s) - (cond - [(my-circle? s) (my-circle-weight s)] - [(my-square? s) (my-square-weight s)] - [(my-composite? s) (my-composite-weight s)])) - -;; my-circle-weight, my-square-weight, my-composite-weight : Shape -> Number -;; GIVEN: a shape -;; WHERE: the shape is of the specified variant -;; RETURNS: the weight of the shape, assuming that each shape weighs 1 -;; gram per pixel of area. - -(define (my-circle-weight s) (* pi (my-circle-r s) (my-circle-r s))) -(define (my-square-weight s) (* (my-square-l s) (my-square-l s))) -(define (my-composite-weight s) (+ (weight (my-composite-front s)) - (weight (my-composite-back s)))) - -;; add-to-scene : Shape Scene -> Scene -;; RETURNS: a scene like the given one, but with the given shape -;; painted on it. - -(define (add-to-scene s scene) - (cond - [(my-circle? s) (my-circle-add-to-scene s scene)] - [(my-square? s) (my-square-add-to-scene s scene)] - [(my-composite? s) (my-composite-add-to-scene s scene)])) - - -;; my-circle-add-to-scene, my-square-add-to-scene, -;; my-composite-add-to-scene : Shape Scene -;; GIVEN: A shape and a scene -;; WHERE: the shape is of the specified variant -;; RETURNS: a scene like the given one, but with the given shape -;; painted on it. -;; STRATEGY: Structural Decomposition on each struct -(define (my-circle-add-to-scene s scene) - (local - ((define IMG (circle (my-circle-r s) "solid" (my-circle-color s)))) - (place-image IMG - (my-circle-x s) - (my-circle-y s) - scene))) - -(define (my-square-add-to-scene s scene) - (local - ((define IMG (square (my-square-l s) "solid" (my-square-color s)))) - (place-image IMG - (my-square-x s) - (my-square-y s) - scene))) - -(define (my-composite-add-to-scene s scene) - ;; paint the back image first, then the front image - (add-to-scene (my-composite-front s) - (add-to-scene (my-composite-back s) - scene))) - -(define EMPTY-CANVAS (empty-scene 200 100)) - -(define s1 (make-my-circle 50 20 40 "red")) -(define s2 (make-my-square 80 70 40 "blue")) -(define s3 (make-my-composite s1 s2)) - -(begin-for-test - (check-= (weight s1) (* pi 1600) .1) - (check-equal? (weight s2) 1600) - (check-= (weight s3) (+ (* pi 1600) 1600) .1)) - - - - diff --git a/Examples/09-3-3-shapes-with-interfaces.rkt b/Examples/09-3-3-shapes-with-interfaces.rkt deleted file mode 100644 index 9eb7e0e..0000000 --- a/Examples/09-3-3-shapes-with-interfaces.rkt +++ /dev/null @@ -1,163 +0,0 @@ -#lang racket - -;; 09-3-shapes.rkt - -(require rackunit) -(require "extras.rkt") -(require 2htdp/image) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; A Tiny System for creating and drawing shapes on a canvas. - -;;; demo with (demo) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; We don't know what shapes there will be, but we know what -;; operations we will want on shapes. This is the shape interface: - -;;; INTERFACE: - -;; a Shape is an object of a class that implements Shape<%>. - -(define Shape<%> - (interface () - - ;; weight : -> Number - ;; RETURNS: the weight of this shape - weight - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - add-to-scene - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Classes -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; We will have a class for each kind of shape - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Circles - -;; Constructor Template for Circle%: -;; (new Circle% [x Integer][y Integer][r Integer][c ColorString]) -;; Interpretation: a circle on the canvas. - -(define Circle% - (class* object% (Shape<%>) - (init-field - x ; Integer, x pixels of center from left - y ; Integer, y pixels of center from top - r ; Integer, radius - c) ; ColorString - - (field [IMG (circle r "solid" c)]) - - (super-new) - - ;; for each method, we copy down the contract and purpose - ;; statement from the interface, with perhaps additional details - ;; relating to this class. - - ;; weight : -> Integer - ;; RETURNS: the weight of this shape - ;; DETAILS: this shape is a circle - ;; STRATEGY: combine simpler functions - (define/public (weight) (* pi r r)) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - ;; DETAILS: this shape is a circle - ;; STRATEGY: call a more general function - (define/public (add-to-scene s) (place-image IMG x y s)) - - )) - -;; Constructor Template for Square%: -;; (new Square% [x Integer][y Integer][l Integer][c ColorString]) -;; Interpretation: a square parallel to sides of canvas - - -(define Square% - (class* object% (Shape<%>) - (init-field x ; Integer, x pixels of center from left - y ; Integer, y pixels of center from top - l ; Integer, length of one side - c) ; ColorString - - (field [IMG (rectangle l l "solid" c)]) - - (super-new) - - ;; weight : -> Real - ;; RETURNS: the weight of this shape - ;; DETAILS: this shape is a square - ;; STRATEGY: combine simpler functions - (define/public (weight) (* l l)) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - ;; DETAILS: this shape is a square - ;; STRATEGY: call a more general function - (define/public (add-to-scene s) (place-image IMG x y s)) - - )) - -;; Constructor Template for Composite%: -;; a (new Composite% [front Shape][back Shape]) -;; Interpretation: a composite of front and back shapes - -(define Composite% - (class* object% (Shape<%>) - (init-field - front ; Shape, the shape in front - back ; Shape, the shape in back - ) - - (super-new) - - ;; all we know here is that front and back implement Shape<%>. - ;; we don't know if they are circles, squares, or other composites! - - ;; weight : -> Number - ;; RETURNS: the weight of this shape - ;; DETAILS: this shape is a composite - ;; STRATEGY: recur on the components - (define/public (weight) (+ (send front weight) - (send back weight))) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - ;; DETAILS: this shape is a composite - ;; strategy: recur on the components - (define/public (add-to-scene scene) - (send front add-to-scene - (send back add-to-scene scene))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define EMPTY-CANVAS (empty-scene 200 100)) - -(define s1 (new Circle% [x 50][y 20][r 40][c "red"])) -(define s2 (new Square% [x 80][y 70][l 40][c "blue"])) -(define s3 (new Composite% [front s1][back s2])) - - -(begin-for-test - (check-= (send s1 weight) (* pi 1600) .1) - (check-equal? (send s2 weight) 1600) - (check-= (send s3 weight) (+ (* pi 1600) 1600) .1)) - -(define (demo) - (send s3 add-to-scene EMPTY-CANVAS)) diff --git a/Examples/09-4-testing.rkt b/Examples/09-4-testing.rkt deleted file mode 100644 index b6b5401..0000000 --- a/Examples/09-4-testing.rkt +++ /dev/null @@ -1,178 +0,0 @@ -#lang racket - -(require "extras.rkt") -(require rackunit) - -;; A StupidRobot is an object of any class that implements -;; StupidRobot<%> - -;; Interpretation: A StupidRobot represents a robot moving along a -;; one-dimensional line, starting at position 0. - -(define StupidRobot<%> - (interface () - - ;; a new StupidRobot<%> is required to start at position 0 - - ;; -> StupidRobot - ;; RETURNS: a Robot just like this one, except moved one - ;; position to the right - move-right - - ;; -> Integer - ;; RETURNS: the current x-position of this robot - get-pos - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Client Code of Interface - -;; move-right-by-distance : Robot<%> Nat -> Robot<%> -(define (move-right-by-distance r n) - (cond - [(zero? n) r] - [else (move-right-by-distance - (send r move-right) - (- n 1))])) - -;;; tests - -(begin-for-test - (local - ((define r0 (new-robot)) - ;; move r0 right twice - (define r1 (send (send r0 move-right) move-right))) - ;; get-pos should then return 2 - (check-equal? - (send r1 get-pos) - 2))) - -(begin-for-test - (local - ((define r0 (new-robot)) - (define r1 (move-right-by-distance r0 3))) - (check-equal? - (send r1 get-pos) - 3))) - -;; let's create a bunch of robots and see if our tests pass for all of them -(begin-for-test - (let ((the-robots (map (lambda (n) (new-robot)) '(1 2 3 4 5 6 7 8 9 10)))) - (map - (lambda (r) (let ((r1 (move-right-by-distance r 13))) - (check-equal? - (send r1 get-pos) - 13))) - the-robots))) - - -(begin-for-test - (let ((r1 (new Robot1%)) - (r2 (new Robot1%))) - (check-equal? r1 r2 "This is an expected failure"))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Implementations - -;; Constructor Template for Robot1%: -;; (new Robot1% [x NonNegInt]) -;; x is optional; default is 0 - -(define Robot1% - (class* object% (StupidRobot<%>) - - (init-field [x 0]) - ;; interp: the position of the robot, initially 0 - - (super-new) - - (define/public (move-right) - (new Robot1% [x (+ x 1)])) - - (define/public (get-pos) - x) - - )) - -;; Constructor Template for Robot2%: -;; (new Robot2% [blerch NonNegInt]) -;; blerch is optional; default is 0 - -(define Robot2% - (class* object% (StupidRobot<%>) - - (init-field [blerch 0]) - ;; interp: the position of the robot. - - (super-new) - - (define/public (move-right) - (new Robot2% [blerch (+ blerch 1)])) - - (define/public (get-pos) - blerch) - - )) - -;; Constructor Template for Robot3%: -;; (new Robot3% [y NonNegInt]) -;; y is the negative of the position of the robot -;; y is optional; default is 0 - -(define Robot3% - (class* object% (StupidRobot<%>) - - (init-field [y 0]) - ;; interp: the negative of the position of the robot. - - (super-new) - - (define/public (move-right) - (new Robot3% [y (- y 1)])) - - ;; RETURNS: the x-position of the robot - (define/public (get-pos) - (- y)) - - )) - -;; Constructor Template for Robot4%: -;; (new Robot4% [y ListOfRacketValue]) -;; x is any Racket list whose length is equal to the position of the -;; robot. -;; x is optional; default is 0 - -(define Robot4% - (class* object% (StupidRobot<%>) - - (init-field [x empty]) - ;; Interp: - ;; a list whose length is equal to the position of the robot - - (super-new) - - (define/public (move-right) - (new Robot4% [x (cons 99 x)])) - - ;; RETURNS: the x-position of the robot - (define/public (get-pos) - (length x)) - - )) - -;; -> StupidRobot<%> -(define (new-robot) - (local - ((define i (random 3))) - (cond - [(= i 0) (new Robot1%)] - [(= i 1) (new Robot2%)] - [(= i 2) (new Robot3%)] - [(= i 3) (new Robot4%)]))) - - - - diff --git a/Examples/09-7-coding-standards.rkt b/Examples/09-7-coding-standards.rkt deleted file mode 100644 index 540e349..0000000 --- a/Examples/09-7-coding-standards.rkt +++ /dev/null @@ -1,40 +0,0 @@ -#lang racket - -;; illustrations for coding examples - -(define Foo<%> - (interface () - - ; -> Integer - ; purpose statement omitted... - m1 - - ; Bar -> Foo - ; purpose statement omitted... - add-bar)) - -(define Class1% - (class* object% (Foo<%>) - - (init-field ...) - (field [LOCAL-CONSTANT ...]) - (super-new) - - ; m1 : -> Integer - ; purpose statement omitted... - (define/public (m1) ...) - - ; add-bar : Bar -> Foo - (define/public (add-bar b) ...) - - ;; (define/public (method-not-in-interface ...) ...) - - - (define (private-function1 ...) ...) - (define (private-function2 ...) ...) - - ;; for-test:... methods don't need to be in the interface - - (define/public (for-test:test-fcn1 ...) ...) - - )) \ No newline at end of file diff --git a/Examples/10-1-Alist-v2-spec/AList.java b/Examples/10-1-Alist-v2-spec/AList.java new file mode 100644 index 0000000..a86e01b --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-1-Alist-v2-spec/ALists.java b/Examples/10-1-Alist-v2-spec/ALists.java new file mode 100644 index 0000000..547325f --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/ALists.java @@ -0,0 +1,25 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class ALists { + + // this generates a new EmptyAList object every time it is called. + public static AList empty () { + return new EmptyAList (); + } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-1-Alist-v2-spec/EmptyAlist.java b/Examples/10-1-Alist-v2-spec/EmptyAlist.java new file mode 100644 index 0000000..3170ec6 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/EmptyAlist.java @@ -0,0 +1,36 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString() { return "%"; } + +} diff --git a/Examples/10-1-Alist-v2-spec/NonEmptyAList.java b/Examples/10-1-Alist-v2-spec/NonEmptyAList.java new file mode 100644 index 0000000..08c6659 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/NonEmptyAList.java @@ -0,0 +1,54 @@ +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K otherKey) { + if (otherKey.equals (this.key)) + return true; + else + return rest.contains (otherKey); + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString () { + return ("[" + + this.key.toString() +":" + this.val.toString() + + "]" + this.rest.toString() + ); + } + + + +} diff --git a/Examples/10-1-Alist-v2-spec/README b/Examples/10-1-Alist-v2-spec/README new file mode 100644 index 0000000..25b7f4e --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/README @@ -0,0 +1,4 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist + diff --git a/Examples/10-1-Alist-v2-spec/SimpleChecks.java b/Examples/10-1-Alist-v2-spec/SimpleChecks.java new file mode 100644 index 0000000..3a645b0 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/SimpleChecks.java @@ -0,0 +1,38 @@ +class SimpleChecks { + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-1-Alist-v2-spec/Tests.java b/Examples/10-1-Alist-v2-spec/Tests.java new file mode 100644 index 0000000..4347fd3 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/Tests.java @@ -0,0 +1,92 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + checkTrue (a1.lookup ("x") == 1); + + checkTrue (a2.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + + checkTrue (a3.lookup ("x") == 1); + checkTrue (a3.lookup ("y") == 2); + checkTrue (a3.lookup ("z") == 3); + + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + System.out.println(a1.toString()); + System.out.println(a2.toString()); + System.out.println(a3.toString()); + System.out.println(a4.toString()); + + + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkFalse (a0.contains ("x")); + checkTrue (a3.contains ("z")); + checkTrue (a4.contains ("x")); + checkFalse (a4.contains ("b")); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + + checkTrue (b2.lookup ("x") == 1); + checkTrue (b2.lookup ("y") == 2); + checkTrue (b4.lookup ("x") == 33); + checkTrue (b4.lookup ("y") == 44); + checkTrue (b4.lookup ("b") == 22); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-1-UTCv3/UTC.java b/Examples/10-1-UTCv3/UTC.java deleted file mode 100644 index a614ee9..0000000 --- a/Examples/10-1-UTCv3/UTC.java +++ /dev/null @@ -1,18 +0,0 @@ -// A UTC is an object of any class that implements UTC. -// -// Interpretation: A UTC represents a Universal Coordinated Time. - -interface UTC { - - // Returns the hour, between 0 and 23 inclusive. - - int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - boolean isEqual (UTC t2); -} diff --git a/Examples/10-1-UTCv3/UTC1.java b/Examples/10-1-UTCv3/UTC1.java deleted file mode 100644 index df3be8a..0000000 --- a/Examples/10-1-UTCv3/UTC1.java +++ /dev/null @@ -1,80 +0,0 @@ -// Constructor template for UTC1: -// new UTC1 (h, m) -// Interpretation: -// h is the hour (between 0 and 23, inclusive) -// m is the minute (between 0 and 59, inclusive) - -class UTC1 implements UTC { - - int h; // the hour, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC1 (int h, int m) { - this.h = h; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { return h; } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return UTCs.isEqual (this, t2); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return UTCs.hashCode (this); - } - - public String toString () { - return UTCs.toString (this); - } - - // a main method for unit testing - - public static void main (String[] args) { - UTC1tests.main(args); - } -} - -// Unit tests for UTC1. - -class UTC1tests { - - public static void main (String[] args) { - UTC t1 = new UTC1 (15, 31); - UTC t2 = new UTC1 (14, 31); - UTC t3 = new UTC1 (15, 32); - UTC t4 = new UTC1 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC1 passed."); - } -} diff --git a/Examples/10-1-UTCv3/UTC2.java b/Examples/10-1-UTCv3/UTC2.java deleted file mode 100644 index 72b5cbd..0000000 --- a/Examples/10-1-UTCv3/UTC2.java +++ /dev/null @@ -1,66 +0,0 @@ -// Constructor template for UTC2: -// new UTC2 (h, m) -// Interpretation: -// h is the UTC hour (between 0 and 23, inclusive) -// m is the UTC minute (between 0 and 59, inclusive) -// Representation: -// Internally, the hour is represented in Eastern Standard Time, -// which is five hours behind UTC. - -class UTC2 extends UTC1 implements UTC { - - // the h field inherited from UTC1 will not be used - // we will use the following h field instead - - int h; // the hour in EST, limited to [0,23] - - // the Java constructor - - UTC2 (int h, int m) { - super (h, m); // calls the constructor for UTC1 - this.h = (h >= 5) ? (h - 5) : h + 19; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - @Override - public int hour () { - if (h < 19) - return h + 5; - else - return h - 19; - } - - // The minute, isEqual, equals, hashCode, and toString - // methods are inherited from UTC1. - - // a main method for unit testing - - public static void main (String[] args) { - UTC2tests.main(args); - } -} - -// Unit tests for UTC2. - -class UTC2tests { - - public static void main (String[] args) { - UTC t1 = new UTC2 (15, 31); - UTC t2 = new UTC2 (14, 31); - UTC t3 = new UTC2 (15, 32); - UTC t4 = new UTC2 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC2 passed."); - } -} \ No newline at end of file diff --git a/Examples/10-1-UTCv3/UTCs.java b/Examples/10-1-UTCv3/UTCs.java deleted file mode 100644 index 30660ae..0000000 --- a/Examples/10-1-UTCv3/UTCs.java +++ /dev/null @@ -1,145 +0,0 @@ -// In Java, it is often convenient to define static methods -// that deal with some interface type in a separate class -// that does not itself implement the interface. -// -// By convention, the name of that class is the plural of the -// name of the interface. -// -// For example: Collections is a class that defines static methods -// for the Collection type. - -import java.util.Random; - -// The UTCs class defines static methods for the UTC type. -// In particular, it defines a static factory method for creating -// values of the UTC type. - -public class UTCs { - - // Dynamic isEqual methods should delegate to this static method. - - public static boolean isEqual (UTC t1, UTC t2) { - return (t1.hour() == t2.hour()) && (t1.minute() == t2.minute()); - } - - // Dynamic hashCode methods should delegate to this static method. - - public static int hashCode (UTC t) { - return 100 * t.hour() + t.minute(); - } - - // Dynamic toString methods should delegate to this static method. - - public static String toString (UTC t) { - return ((Integer) (100 * t.hour() + t.minute())).toString(); - } - - // random number generator, to be used as a coin flip - - private static Random coinFlips = new Random(); - - // static factory method for creating a UTC - // GIVEN: the hour in [0,23] and the minute in [0,59] - // RETURNS: a UTC with that hour and minute - - public static UTC make (int h, int m) { - // flips a coin to decide whether to return an object - // of class UTC1 or UTC2 - - if (coinFlips.nextBoolean()) - return new UTC1 (h, m); - else - return new UTC2 (h, m); - } - - // main method for testing - - public static void main (String[] args) { - for (String arg : args) - System.out.println (arg); - UTCsTests.main (args); - } -} - -// Tests for UTC objects created by the static factory method in UTCs. - -class UTCsTests { - - public static void main (String[] args) { - - // We'll do these tests several times, to increase the - // probability that objects of different classes will be created. - - int NTESTS = 5; // how many times we'll run each test - - for (int i = 0; i < NTESTS; i = i + 1) { - UTC t0000 = UTCs.make (0, 0); // always test boundary cases - UTC t0059 = UTCs.make (0, 59); - UTC t2300 = UTCs.make (23, 0); - UTC t2359 = UTCs.make (23, 59); - UTC t1531 = UTCs.make (15, 31); // and test typical cases - - assert t0000.hour() == 0 : "wrong hour for t0000"; - assert t0000.minute() == 0 : "wrong minute for t0000"; - assert t0059.hour() == 0 : "wrong hour for t0059"; - assert t0059.minute() == 59 : "wrong minute for t0059"; - assert t2300.hour() == 23 : "wrong hour for t2300"; - assert t2300.minute() == 0 : "wrong minute for t2300"; - assert t2359.hour() == 23 : "wrong hour for t2359"; - assert t2359.minute() == 59 : "wrong minute for t2359"; - assert t1531.hour() == 15 : "wrong hour for t1531"; - assert t1531.minute() == 31 : "wrong minute for t1531"; - - assert t0000.isEqual(t0000) : "isEqual says t0000 != t0000"; - assert t0059.isEqual(t0059) : "isEqual says t0059 != t0059"; - assert t2300.isEqual(t2300) : "isEqual says t2300 != t2300"; - assert t2359.isEqual(t2359) : "isEqual says t2359 != t2359"; - assert t1531.isEqual(t1531) : "isEqual says t1531 != t1531"; - - assert t0000.isEqual(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.isEqual(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.isEqual(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.isEqual(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.isEqual(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.isEqual(t0059)) : "isEqual says t0000 = t0059"; - assert ! (t0059.isEqual(t2359)) : "isEqual says t0059 = t2359"; - assert ! (t2359.isEqual(t2300)) : "isEqual says t2359 = t2300"; - - // tests of the usual triumvirate - - assert t0000.equals(t0000) : "equals says t0000 != t0000"; - assert t0059.equals(t0059) : "equals says t0059 != t0059"; - assert t2300.equals(t2300) : "equals says t2300 != t2300"; - assert t2359.equals(t2359) : "equals says t2359 != t2359"; - assert t1531.equals(t1531) : "equals says t1531 != t1531"; - - assert t0000.equals(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.equals(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.equals(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.equals(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.equals(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.equals(t0059)) : "equals says t0000 = t0059"; - assert ! (t0059.equals(t2359)) : "equals says t0059 = t2359"; - assert ! (t2359.equals(t2300)) : "equals says t2359 = t2300"; - - assert ! (t0000.equals(null)) : "equals says t0000 = null"; - assert ! (t0059.equals("foo")) : "equals says t0059 = a string"; - - assert t0000.hashCode() == (UTCs.make(0, 0).hashCode()); - assert t0059.hashCode() == (UTCs.make(0, 59).hashCode()); - assert t2300.hashCode() == (UTCs.make(23, 0).hashCode()); - assert t2359.hashCode() == (UTCs.make(23, 59).hashCode()); - assert t1531.hashCode() == (UTCs.make(15, 31).hashCode()); - - assert t0000.toString().equals(UTCs.make(0, 0).toString()); - assert t0059.toString().equals(UTCs.make(0, 59).toString()); - assert t2300.toString().equals(UTCs.make(23, 0).toString()); - assert t2359.toString().equals(UTCs.make(23, 59).toString()); - assert t1531.toString().equals(UTCs.make(15, 31).toString()); - } - - System.out.println ("UTCs tests passed."); - } -} \ No newline at end of file diff --git a/Examples/10-1-communicating-objects.rkt b/Examples/10-1-communicating-objects.rkt deleted file mode 100644 index 40a97ea..0000000 --- a/Examples/10-1-communicating-objects.rkt +++ /dev/null @@ -1,190 +0,0 @@ -#lang racket - -(require rackunit) -(require "extras.rkt") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Balls Communicating with an external agent -;;; this is considered poor OO design -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A Ball0 is an object of any class that implements Ball0<%> - -(define Ball0<%> - (interface () - ;; -> Integer - ;; return x, y coords of center and radius, all in pixels - get-x - get-y - get-r)) - -;; Constructor Template for Ball1%: -;; (new Ball1% [x Integer][y Integer][r Integer]) - -(define Ball0% - (class* object% (Ball0<%>) - (init-field x y r) ; interpretation omitted... - (super-new) - (define/public (get-x) x) - (define/public (get-y) y) - (define/public (get-r) r))) - -;; Ball0 Ball0 -> Boolean -;; Do these two balls intersect? -;; This is an ordinary function, outside of any class. -(define (intersects? b1 b2) - (circles-intersect? - (send b1 get-x) (send b1 get-y) (send b1 get-r) - (send b2 get-x) (send b2 get-y) (send b2 get-r))) - -;; Would balls with these coordinates intersect? -(define (circles-intersect? x1 y1 r1 x2 y2 r2) - (<= - (+ (sqr (- x1 x2)) (sqr (- y1 y2))) - (sqr (+ r1 r2)))) - -(begin-for-test - - (check-true - (let ((ball1 (new Ball0% [x 0][y 0][r 10])) - (ball2 (new Ball0% [x 0][y 10][r 10]))) - (and - (intersects? ball1 ball2) - (intersects? ball2 ball1)))) - - (check-false - (let ((ball1 (new Ball0% [x 0][y 0][r 10])) - (ball2 (new Ball0% [x 20][y 10][r 10]))) - (or - (intersects? ball1 ball2) - (intersects? ball2 ball1))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; BALLS COMMUNICATING BY PULL -;; computation gets done in this ball -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A Ball1 is an object of any class that implements Ball1<%> - -(define Ball1<%> - (interface () - ;; -> Integer - ;; return x, y coords of center and radius, all in pixels - get-x - get-y - get-r - - ;; Ball1 -> Boolean - ;; Does this ball intersect the other one? - intersects? - )) - -;; Constructor Template for Ball1%: -;; (new Ball1% [x Integer][y Integer][r Integer]) - -(define Ball1% - (class* object% (Ball-Pull<%>) - (init-field x y r) ; interpretation omitted... - (super-new) - - ;; Does the other ball intersect this one? - ;; STRATEGY: Ask the other ball for its data - (define/public (intersects? other-b) - (coordinates-intersect? - (send other-b get-x) - (send other-b get-y) - (send other-b get-r))) - - ;; Integer^3 -> Boolean - ;; GIVEN: the coordinates of some ball - ;; RETURNS: would that ball intersect this one? - ;; This is a private method (an ordinary function, but inside the - ;; class). Note that it refers to the fields of this object. - (define (coordinates-intersect? other-x other-y other-r) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr (+ r other-r)))) - - (define/public (get-x) x) - (define/public (get-y) y) - (define/public (get-r) r) - -)) - -(begin-for-test - - (check-true - (let ((ball1 (new Ball1% [x 0][y 0][r 10])) - (ball2 (new Ball1% [x 0][y 10][r 10]))) - (and - (send ball1 intersects? ball2) - (send ball2 intersects? ball1)))) - - (check-false - (let ((ball1 (new Ball1% [x 0][y 0][r 10])) - (ball2 (new Ball1% [x 20][y 10][r 10]))) - (or - (send ball1 intersects? ball2) - (send ball2 intersects? ball1))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; BALLS COMMUNICATING BY PUSH -;;; computation gets done in other-ball -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define Ball2<%> - (interface () - - ;; not needed for this example! - ;; ;; -> Integer - ;; ;; return x, y coords of center and radius, all in pixels - ;; get-x - ;; get-y - ;; get-r - - ;; Ball2 -> Boolean - ;; does this ball intersect the other one? - intersects? - - ;; Integer^3 -> Boolean - ;; Would a ball with the given x,y,r intersect this one? - intersect-responder - - )) - -;; Constructor Template for Ball2%: -;; (new Ball2% [x Integer][y Integer][r Integer]) - -(define Ball2% - (class* object% (Ball-Push<%>) - (init-field x y r) ; interpretation omitted... - (super-new) - - ;; Ball2 -> Boolean - (define/public (intersects? other-b) - (send other-b intersect-responder x y r)) - - ;; Integer^3 -> Boolean - (define/public (intersect-responder other-x other-y other-r) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr (+ r other-r)))) - )) - - -(begin-for-test - - (check-true - (let ((ball1 (new Ball2% [x 0][y 0][r 10])) - (ball2 (new Ball2% [x 0][y 10][r 10]))) - (and - (send ball1 intersects? ball2) - (send ball2 intersects? ball1)))) - - (check-false - (let ((ball1 (new Ball2% [x 0][y 0][r 10])) - (ball2 (new Ball2% [x 20][y 10][r 10]))) - (or - (send ball1 intersects? ball2) - (send ball2 intersects? ball1))))) - - - diff --git a/Examples/10-2-Alist-v3-singletons/AList.java b/Examples/10-2-Alist-v3-singletons/AList.java new file mode 100644 index 0000000..a86e01b --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-2-Alist-v3-singletons/ALists.java b/Examples/10-2-Alist-v3-singletons/ALists.java new file mode 100644 index 0000000..91d4601 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/ALists.java @@ -0,0 +1,36 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +import java.util.NoSuchElementException; + +class ALists { + + private static AList theEmptyAList = new EmptyAList(); + + // static factory method for creating an empty AList + + @SuppressWarnings("unchecked") + public static AList empty () { + return (AList) theEmptyAList; + } + + // // this generates a new EmptyAList object every time it is called. + // public static AList empty () { + // return new EmptyAList (); + // } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-2-Alist-v3-singletons/EmptyAlist.java b/Examples/10-2-Alist-v3-singletons/EmptyAlist.java new file mode 100644 index 0000000..1c88989 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/EmptyAlist.java @@ -0,0 +1,36 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + +} diff --git a/Examples/10-2-Alist-v3-singletons/NonEmptyAList.java b/Examples/10-2-Alist-v3-singletons/NonEmptyAList.java new file mode 100644 index 0000000..890737b --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/NonEmptyAList.java @@ -0,0 +1,45 @@ +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + if (key.equals (this.key)) + return true; + else + return rest.contains (key); + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + +} diff --git a/Examples/10-2-Alist-v3-singletons/README b/Examples/10-2-Alist-v3-singletons/README new file mode 100644 index 0000000..a23ac79 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/README @@ -0,0 +1,4 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist +10-2: Adds singleton pattern diff --git a/Examples/10-2-Alist-v3-singletons/Tests.java b/Examples/10-2-Alist-v3-singletons/Tests.java new file mode 100644 index 0000000..0d49c51 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/Tests.java @@ -0,0 +1,77 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkFalse (a0.contains ("x")); + checkTrue (a3.contains ("z")); + checkTrue (a4.contains ("x")); + checkFalse (a4.contains ("b")); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + checkTrue (b2.lookup ("x") == 1); + checkTrue (b2.lookup ("y") == 2); + checkTrue (b4.lookup ("x") == 33); + checkTrue (b4.lookup ("y") == 44); + checkTrue (b4.lookup ("b") == 22); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-2-UTCv4/UTC.java b/Examples/10-2-UTCv4/UTC.java deleted file mode 100644 index a614ee9..0000000 --- a/Examples/10-2-UTCv4/UTC.java +++ /dev/null @@ -1,18 +0,0 @@ -// A UTC is an object of any class that implements UTC. -// -// Interpretation: A UTC represents a Universal Coordinated Time. - -interface UTC { - - // Returns the hour, between 0 and 23 inclusive. - - int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - boolean isEqual (UTC t2); -} diff --git a/Examples/10-2-UTCv4/UTC0.java b/Examples/10-2-UTCv4/UTC0.java deleted file mode 100644 index 04bd9be..0000000 --- a/Examples/10-2-UTCv4/UTC0.java +++ /dev/null @@ -1,43 +0,0 @@ -// Abstract base class for classes that implement the UTC interface. - -abstract class UTC0 implements UTC { - - // the Java constructor has no fields to initialize - // (all fields will be defined in concrete subclasses) - - UTC0 () { } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public abstract int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - public abstract int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return (this.hour() == t2.hour()) && (this.minute() == t2.minute()); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return 100 * this.hour() + this.minute(); - } - - public String toString () { - return ((Integer) (100 * this.hour() + this.minute())).toString(); - } -} diff --git a/Examples/10-2-UTCv4/UTC1.java b/Examples/10-2-UTCv4/UTC1.java deleted file mode 100644 index 65ec056..0000000 --- a/Examples/10-2-UTCv4/UTC1.java +++ /dev/null @@ -1,59 +0,0 @@ -// Constructor template for UTC1: -// new UTC1 (h, m) -// Interpretation: -// h is the hour (between 0 and 23, inclusive) -// m is the minute (between 0 and 59, inclusive) - -class UTC1 extends UTC0 implements UTC { - - int h; // the hour, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC1 (int h, int m) { - this.h = h; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { return h; } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // The isEqual, equals, hashCode, and toString - // methods are inherited from UTC0. - - // a main method for unit testing - - public static void main (String[] args) { - UTC1tests.main(args); - } -} - -// Unit tests for UTC1. - -class UTC1tests { - - public static void main (String[] args) { - UTC t1 = new UTC1 (15, 31); - UTC t2 = new UTC1 (14, 31); - UTC t3 = new UTC1 (15, 32); - UTC t4 = new UTC1 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC1 passed."); - } -} diff --git a/Examples/10-2-UTCv4/UTC2.java b/Examples/10-2-UTCv4/UTC2.java deleted file mode 100644 index bc1d49a..0000000 --- a/Examples/10-2-UTCv4/UTC2.java +++ /dev/null @@ -1,67 +0,0 @@ -// Constructor template for UTC2: -// new UTC2 (h, m) -// Interpretation: -// h is the UTC hour (between 0 and 23, inclusive) -// m is the UTC minute (between 0 and 59, inclusive) -// Representation: -// Internally, the hour is represented in Eastern Standard Time, -// which is five hours behind UTC. - -class UTC2 extends UTC0 implements UTC { - - int h; // the hour in EST, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC2 (int h, int m) { - super (); // calls the constructor for UTC0 - this.h = (h >= 5) ? (h - 5) : h + 19; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { - if (h < 19) - return h + 5; - else - return h - 19; - } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // The isEqual, equals, hashCode, and toString - // methods are inherited from UTC0. - - // a main method for unit testing - - public static void main (String[] args) { - UTC2tests.main(args); - } -} - -// Unit tests for UTC2. - -class UTC2tests { - - public static void main (String[] args) { - UTC t1 = new UTC2 (15, 31); - UTC t2 = new UTC2 (14, 31); - UTC t3 = new UTC2 (15, 32); - UTC t4 = new UTC2 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC2 passed."); - } -} \ No newline at end of file diff --git a/Examples/10-2-UTCv4/UTCs.java b/Examples/10-2-UTCv4/UTCs.java deleted file mode 100644 index 30660ae..0000000 --- a/Examples/10-2-UTCv4/UTCs.java +++ /dev/null @@ -1,145 +0,0 @@ -// In Java, it is often convenient to define static methods -// that deal with some interface type in a separate class -// that does not itself implement the interface. -// -// By convention, the name of that class is the plural of the -// name of the interface. -// -// For example: Collections is a class that defines static methods -// for the Collection type. - -import java.util.Random; - -// The UTCs class defines static methods for the UTC type. -// In particular, it defines a static factory method for creating -// values of the UTC type. - -public class UTCs { - - // Dynamic isEqual methods should delegate to this static method. - - public static boolean isEqual (UTC t1, UTC t2) { - return (t1.hour() == t2.hour()) && (t1.minute() == t2.minute()); - } - - // Dynamic hashCode methods should delegate to this static method. - - public static int hashCode (UTC t) { - return 100 * t.hour() + t.minute(); - } - - // Dynamic toString methods should delegate to this static method. - - public static String toString (UTC t) { - return ((Integer) (100 * t.hour() + t.minute())).toString(); - } - - // random number generator, to be used as a coin flip - - private static Random coinFlips = new Random(); - - // static factory method for creating a UTC - // GIVEN: the hour in [0,23] and the minute in [0,59] - // RETURNS: a UTC with that hour and minute - - public static UTC make (int h, int m) { - // flips a coin to decide whether to return an object - // of class UTC1 or UTC2 - - if (coinFlips.nextBoolean()) - return new UTC1 (h, m); - else - return new UTC2 (h, m); - } - - // main method for testing - - public static void main (String[] args) { - for (String arg : args) - System.out.println (arg); - UTCsTests.main (args); - } -} - -// Tests for UTC objects created by the static factory method in UTCs. - -class UTCsTests { - - public static void main (String[] args) { - - // We'll do these tests several times, to increase the - // probability that objects of different classes will be created. - - int NTESTS = 5; // how many times we'll run each test - - for (int i = 0; i < NTESTS; i = i + 1) { - UTC t0000 = UTCs.make (0, 0); // always test boundary cases - UTC t0059 = UTCs.make (0, 59); - UTC t2300 = UTCs.make (23, 0); - UTC t2359 = UTCs.make (23, 59); - UTC t1531 = UTCs.make (15, 31); // and test typical cases - - assert t0000.hour() == 0 : "wrong hour for t0000"; - assert t0000.minute() == 0 : "wrong minute for t0000"; - assert t0059.hour() == 0 : "wrong hour for t0059"; - assert t0059.minute() == 59 : "wrong minute for t0059"; - assert t2300.hour() == 23 : "wrong hour for t2300"; - assert t2300.minute() == 0 : "wrong minute for t2300"; - assert t2359.hour() == 23 : "wrong hour for t2359"; - assert t2359.minute() == 59 : "wrong minute for t2359"; - assert t1531.hour() == 15 : "wrong hour for t1531"; - assert t1531.minute() == 31 : "wrong minute for t1531"; - - assert t0000.isEqual(t0000) : "isEqual says t0000 != t0000"; - assert t0059.isEqual(t0059) : "isEqual says t0059 != t0059"; - assert t2300.isEqual(t2300) : "isEqual says t2300 != t2300"; - assert t2359.isEqual(t2359) : "isEqual says t2359 != t2359"; - assert t1531.isEqual(t1531) : "isEqual says t1531 != t1531"; - - assert t0000.isEqual(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.isEqual(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.isEqual(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.isEqual(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.isEqual(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.isEqual(t0059)) : "isEqual says t0000 = t0059"; - assert ! (t0059.isEqual(t2359)) : "isEqual says t0059 = t2359"; - assert ! (t2359.isEqual(t2300)) : "isEqual says t2359 = t2300"; - - // tests of the usual triumvirate - - assert t0000.equals(t0000) : "equals says t0000 != t0000"; - assert t0059.equals(t0059) : "equals says t0059 != t0059"; - assert t2300.equals(t2300) : "equals says t2300 != t2300"; - assert t2359.equals(t2359) : "equals says t2359 != t2359"; - assert t1531.equals(t1531) : "equals says t1531 != t1531"; - - assert t0000.equals(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.equals(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.equals(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.equals(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.equals(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.equals(t0059)) : "equals says t0000 = t0059"; - assert ! (t0059.equals(t2359)) : "equals says t0059 = t2359"; - assert ! (t2359.equals(t2300)) : "equals says t2359 = t2300"; - - assert ! (t0000.equals(null)) : "equals says t0000 = null"; - assert ! (t0059.equals("foo")) : "equals says t0059 = a string"; - - assert t0000.hashCode() == (UTCs.make(0, 0).hashCode()); - assert t0059.hashCode() == (UTCs.make(0, 59).hashCode()); - assert t2300.hashCode() == (UTCs.make(23, 0).hashCode()); - assert t2359.hashCode() == (UTCs.make(23, 59).hashCode()); - assert t1531.hashCode() == (UTCs.make(15, 31).hashCode()); - - assert t0000.toString().equals(UTCs.make(0, 0).toString()); - assert t0059.toString().equals(UTCs.make(0, 59).toString()); - assert t2300.toString().equals(UTCs.make(23, 0).toString()); - assert t2359.toString().equals(UTCs.make(23, 59).toString()); - assert t1531.toString().equals(UTCs.make(15, 31).toString()); - } - - System.out.println ("UTCs tests passed."); - } -} \ No newline at end of file diff --git a/Examples/10-2-ball-and-wall.rkt b/Examples/10-2-ball-and-wall.rkt deleted file mode 100644 index 85747a1..0000000 --- a/Examples/10-2-ball-and-wall.rkt +++ /dev/null @@ -1,450 +0,0 @@ -#lang racket - -;; 10-2-1-ball-and-wall.rkt - -;; the world will be an object with exactly two widgets: -;; a ball and a wall. - -;; In this version, the wall is draggable, but the ball is not. -;; The ball should bounce off the wall. - -;; The ball is told about the wall when it's created - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 8) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; A World is an object of any class that implements World<%> - -(define World<%> - (interface () - - ; -> World - ; GIVEN: no arguments - ; RETURNS: the state of the world at the next tick - after-tick - - ; Integer Integer MouseEvent-> World - ; GIVEN: a location - ; RETURNS: the state of the world that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> World - ; GIVEN: a key event - ; RETURNS: the state of the world that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - )) - - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; Additional method for Wall. - -;; A Wall is an object of any class that implements Wall<%>. -;; There will be only one such class - -(define Wall<%> - (interface (Widget<%>) - - ; -> Int - ; RETURNS: the x-position of the wall - get-pos - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; initial-world : -> World -;; RETURNS: a world with -(define (initial-world) - (local - ((define the-wall (new Wall%)) - (define the-ball (new Ball% [w the-wall]))) - (make-world - (list the-wall the-ball)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the final state of the world -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (send w after-tick)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (send w after-key-event kev))) - (on-mouse - (lambda (w mx my mev) - (send w after-mouse-event mx my mev))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The World% class - -;; In this example, the world will have exactly two widgets in it. -;; To get perfect marks on design, we would rewrite the World% class -;; to reflect this invariant to replace the ListOfWidget by two -;; init-fields. But this is a special situation for this example only, -;; so we don't take the effort to do this. - -; ListOfWidget -> World -(define (make-world objs) - (new World% [objs objs])) - -(define World% - (class* object% (World<%>) - - (init-field objs) ; ListOfWidget - - (super-new) - - ;; after-tick : -> World - ;; Use HOFC map on the Widgets in this World - (define/public (after-tick) - (make-world - (map - (lambda (obj) (send obj after-tick)) - objs))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets in this World - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - objs)) - - ;; after-key-event : KeyEvent -> World - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (make-world - (map - (lambda (obj) (send obj after-key-event kev)) - objs))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> World - ;; STRATGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (make-world - (map - (lambda (obj) (send obj after-button-down mx my)) - objs))) - - - (define (world-after-button-up mx my) - (make-world - (map - (lambda (obj) (send obj after-button-up mx my)) - objs))) - - (define (world-after-drag mx my) - (make-world - (map - (lambda (obj) (send obj after-drag mx my)) - objs))) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The Ball% class - -;; A Ball is a (new Ball% [x Int][y Int][speed Int][w Wall]) -;; w is required; all others have default values - -(define Ball% - (class* object% (Widget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - (super-new) - - ;; after-tick : -> Ball - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? this - (new Ball% - [x (next-x-pos)] - [y y] - [speed (next-speed)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: ask the wall for its position and use that to - ;; calculate the upper bound for the ball's x position - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- (send w get-pos) radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - ;; EXAMPLES: - ;; (limit-value 10 20 30) = 20 - ;; (limit-value 10 5 30) = 10 - ;; (limit-value 10 100 30) = 30 - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if at the next tick, the ball will be at its limit, negate the - ;; velocity, otherwise return the velocity unchanged - (define (next-speed) - (if (or - (= (next-x-pos) radius) - (= (next-x-pos) (- (send w get-pos) radius))) - (- speed) - speed)) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Ball - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)] - [w w]) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this ball. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Ball - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? false] - [saved-mx 127] - [saved-my 98] ; the invariant says that if selected? is - ; false, you can put anything here. - [w w]) - this)) - - ; after-drag : Integer Integer -> Ball - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Ball% - [x (- mx saved-mx)] - [y (- my saved-my)] - [speed speed] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]) - this)) - - ;; the ball ignores key events - (define/public (after-key-event kev) this) - - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The Wall% class - -;; A Wall is (new Wall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values. - -(define Wall% - (class* object% (Wall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - ;; relative to the wall position - (init-field [saved-mx 0]) - - (super-new) - - ;; the extra behavior for Wall<%> - (define/public (get-pos) pos) - - ; after-button-down : Integer Integer -> Wall - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is near the wall - ; RETURNS: A wall like this one, but marked as selected and with - ; the mouse position recorded. - (define/public (after-button-down mx my) - (if (near-wall? mx) - (new Wall% - [pos pos] - [selected? true] - [saved-mx (- mx pos)]) - this)) - - ; after-button-up : Integer Integer -> Wall - ; GIVEN: the location of a button-up event - ; RETURNS: a Wall like this one, but unselected - (define/public (after-button-up mx my) - (new Wall% - [pos pos] - [selected? false] - [saved-mx saved-mx])) - - ; after-drag : Integer Integer -> Wall - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; DETAILS: If this wall is selected, returns a wall like this one, - ; except that the vector from its position to - ; the drag event is equal to saved-mx - (define/public (after-drag mx my) - (if selected? - (new Wall% - [pos (- mx saved-mx)] - [selected? true] - [saved-mx saved-mx]) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/10-3-Alist-v4-sorted/AList.java b/Examples/10-3-Alist-v4-sorted/AList.java new file mode 100644 index 0000000..a5283a4 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList,V> { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-3-Alist-v4-sorted/ALists.java b/Examples/10-3-Alist-v4-sorted/ALists.java new file mode 100644 index 0000000..7551e51 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/ALists.java @@ -0,0 +1,35 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class ALists { + + private static AList theEmptyAList = new EmptyAList(); + + // static factory method for creating an empty AList + + @SuppressWarnings("unchecked") + public static ,V> AList empty () { + return (AList) theEmptyAList; + } + + + // // this generates a new EmptyAList object every time it is called. + // public static AList empty () { + // return new EmptyAList (); + // } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-3-Alist-v4-sorted/EmptyAlist.java b/Examples/10-3-Alist-v4-sorted/EmptyAlist.java new file mode 100644 index 0000000..d50616e --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/EmptyAlist.java @@ -0,0 +1,36 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList,V> implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + public String toString() {return "%";} + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + +} diff --git a/Examples/10-3-Alist-v4-sorted/NonEmptyAList.java b/Examples/10-3-Alist-v4-sorted/NonEmptyAList.java new file mode 100644 index 0000000..783c990 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/NonEmptyAList.java @@ -0,0 +1,64 @@ +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList,V> implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + // maintains the list in sorted order + // use <= so to maintain stable sort for duplicate keys :) + + public AList extend (K newKey, V newVal) { + + if (newKey.compareTo(this.key) <= 0) + return new NonEmptyAList (newKey, newVal, this); + else + return new NonEmptyAList + (this.key, + this.val, + this.rest.extend(newKey,newVal)); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K otherKey) { + if (otherKey.compareTo(this.key) < 0) {return false;} + else if (otherKey.equals (this.key)) + return true; + else + return rest.contains (otherKey); + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString () { + return ("[" + + this.key.toString() +":" + this.val.toString() + + "]" + this.rest.toString() + ); + } + +} diff --git a/Examples/10-3-Alist-v4-sorted/README b/Examples/10-3-Alist-v4-sorted/README new file mode 100644 index 0000000..44c7230 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/README @@ -0,0 +1,5 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist +10-2: Adds singleton pattern +10-3 ADDS: keep keys in order diff --git a/Examples/10-3-Alist-v4-sorted/Tests.java b/Examples/10-3-Alist-v4-sorted/Tests.java new file mode 100644 index 0000000..f5f36b3 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/Tests.java @@ -0,0 +1,95 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkTrue (a1.lookup ("x") == 1); + + checkTrue (a2.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + + checkTrue (a3.lookup ("x") == 1); + checkTrue (a3.lookup ("y") == 2); + checkTrue (a3.lookup ("z") == 3); + + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + System.out.println(a1.toString()); + System.out.println(a2.toString()); + System.out.println(a3.toString()); + System.out.println(a4.toString()); + + checkFalse (a0.contains ("x"), "a0 should not contain x"); + checkTrue (a3.contains ("z"), "a3 should contain z"); + checkTrue (a4.contains ("x"), "a4 should contain x"); + checkFalse (a4.contains ("b"), "a4 should contain x"); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1, "a1(x) should equal 1"); + checkTrue (a2.lookup ("y") == 2, "a2(x) should equal 2"); + checkTrue (a4.lookup ("x") == 1, "a4(x) should equal 1"); + checkTrue (a4.lookup ("y") == 4, "a4(y) should equal 4"); + checkTrue (a4.lookup ("z") == 3, "a4(z) should equal 3"); + + checkTrue (b2.lookup ("x") == 1, "b2(x) should equal 1"); + checkTrue (b2.lookup ("y") == 2, "b2(y) should equal 2"); + checkTrue (b4.lookup ("x") == 33, "b4(x) should equal 33"); + checkTrue (b4.lookup ("y") == 44, "b4(y) should equal 44"); + checkTrue (b4.lookup ("b") == 22, "b4(b) should equal 22"); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + // System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-3-IMapV1/IMap.java b/Examples/10-3-IMapV1/IMap.java deleted file mode 100644 index 7088d4f..0000000 --- a/Examples/10-3-IMapV1/IMap.java +++ /dev/null @@ -1,18 +0,0 @@ -// An IMap is an object of any class that implements IMap. -// -// Interpretation: An IMap represents an immutable finite function -// from keys to values. -// -// IMap extends java.util.Map, so an IMap can be used -// as an unmodifiable Map. - -import java.util.Map; - -interface IMap extends Map { - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - - IMap extend (K key, V value); -} diff --git a/Examples/10-3-IMapV1/IMapList.java b/Examples/10-3-IMapV1/IMapList.java deleted file mode 100644 index 19a813b..0000000 --- a/Examples/10-3-IMapV1/IMapList.java +++ /dev/null @@ -1,114 +0,0 @@ -// Constructor templates for IMapList: -// new IMapList (rktList) -// new IMapList () -// Interpretation: -// rktList is a RacketList -// containing the key/value pairs of the IMap -// where no key is the key for two different key/value pairs -// if rktList is omitted, creates an empty map - -import java.util.Map; -import java.util.Map.Entry; -import java.util.AbstractMap; -import java.util.AbstractMap.SimpleEntry; -import java.util.AbstractMap.SimpleImmutableEntry; - -import java.util.Set; -import java.util.AbstractSet; - -import java.util.Iterator; - -// Strategy, quoted from the documentation for AbstractMap: -// -// To implement an unmodifiable map, the programmer needs only to -// extend [the AbstractMap] class and provide an implementation -// for the entrySet method, which returns a set-view of the map's -// mappings. Typically, the returned set will, in turn, be -// implemented atop AbstractSet. This set should not support the -// add or remove methods, and its iterator should not support the -// remove method. - -class IMapList extends AbstractMap implements IMap { - - RacketList> entries; // set of key/value pairs - - // Java constructors - - IMapList () { - this.entries = RacketLists.empty(); - } - - IMapList (RacketList> entries) { - this.entries = entries; - } - - // public methods listed by IMap interface - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - - public IMap extend (K key, V value) { - Entry entry = new SimpleImmutableEntry (key, value); - return new IMapList (extended (entries, entry)); - } - - // public methods listed by Map interface - - // Returns a set of the key/value pairs in this Map. - - public Set> entrySet () { - return new IMapListSet (entries); - } - - // all other public methods are defined by AbstractMap - - // private help methods - - // Given a RacketList of entries and an entry with key k, - // returns a RacketList in which the given entry replaces - // any entry with key k or, if the given RacketList of entries - // contains no entry with key k, returns a RacketList with - // the given entry added to it. - // - // This method has no side effects. - - private RacketList> extended (RacketList> entries, - Entry entry) { - if (entries.isEmpty()) { - return entries.cons (entry); - } - if (entries.first().getKey().equals (entry.getKey())) { - return entries.rest().cons (entry); - } - else - return extended (entries.rest(), entry).cons (entries.first()); - } -} - -class IMapListSet extends AbstractSet> { - - RacketList> entries; - - // Java constructors - - IMapListSet () { - this.entries = RacketLists.empty(); - } - - IMapListSet (RacketList> entries) { - this.entries = entries; - } - - // public methods - - // Returns an Iterator for the entries in this set. - - public Iterator> iterator () { - return RacketLists.makeIterator (entries); - } - - // Returns the size of this set. - - public int size () { return RacketLists.length (entries); } -} diff --git a/Examples/10-3-IMapV1/IMaps.java b/Examples/10-3-IMapV1/IMaps.java deleted file mode 100644 index 67ad58b..0000000 --- a/Examples/10-3-IMapV1/IMaps.java +++ /dev/null @@ -1,68 +0,0 @@ -// The IMaps class defines static methods for the IMap type. -// In particular, it defines a static factory method for creating the -// empty map of the IMap type. - -import java.util.Iterator; - -class IMaps { - - private static IMap theEmptyIMap = new IMapList(); - - // static factory method for creating an empty IMap - - @SuppressWarnings("unchecked") - public static IMap empty () { - return (IMap) theEmptyIMap; - } - - // main method for testing - - public static void main (String[] args) { - IMapTests.main (args); - } -} - -// Tests for IMap objects. - -class IMapTests { - - public static void main (String[] args) { - IMap m0 = IMaps.empty(); - IMap m1 = m0.extend (1, "one"); - IMap m2 = m0.extend (2, "two"); - IMap m3 = m0.extend (3, "three"); - IMap m4 = m0.extend (4, "four"); - IMap m5 = m0.extend (5, "five"); - IMap m6 = m0.extend (6, "six"); - IMap m7 = m0.extend (7, "seven"); - IMap m8 = m0.extend (8, "eight"); - IMap m9 = m0.extend (9, "nine"); - - IMap m00 = IMaps.empty(); - IMap m03 = m9.extend (3, "drei"); - IMap m10 = m03.extend (10, "zehn"); - - assert ! m0.containsKey(1); - assert m9.containsKey(4); - assert ! m9.containsKey(10); - - assert m9.get(9).equals("nine"); - assert m9.get(3).equals("three"); - assert m9.get(1).equals("one"); - - assert m10.get(9).equals("nine"); - assert m10.get(3).equals("drei"); - assert m10.get(1).equals("one"); - - assert m0.isEmpty(); - assert ! m1.isEmpty(); - - assert m0.size() == 0; - assert m1.size() == 1; - assert m9.size() == 9; - assert m03.size() == 9; - assert m10.size() == 10; - - System.out.println ("IMap tests passed."); - } -} diff --git a/Examples/10-4-Alist-v5-BSTs/AList.java b/Examples/10-4-Alist-v5-BSTs/AList.java new file mode 100644 index 0000000..a5283a4 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList,V> { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-4-Alist-v5-BSTs/ALists.java b/Examples/10-4-Alist-v5-BSTs/ALists.java new file mode 100644 index 0000000..3157b98 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/ALists.java @@ -0,0 +1,36 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class ALists { + + private static AList theEmptyAList = new EmptyAList(); + + // static factory method for creating an empty AList + + @SuppressWarnings("unchecked") + public static ,V> AList empty () { + return (AList) theEmptyAList; + } + + + // // this generates a new EmptyAList object every time it is called. + // // public static AList empty () { + // public static ,V> AList empty () { + // return new EmptyAList (); + // } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-4-Alist-v5-BSTs/EmptyAlist.java b/Examples/10-4-Alist-v5-BSTs/EmptyAlist.java new file mode 100644 index 0000000..a5a041f --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/EmptyAlist.java @@ -0,0 +1,40 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList,V> implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + // returns a new interior node, with both left and right subtrees empty. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString () {return "*";} + +} diff --git a/Examples/10-4-Alist-v5-BSTs/NonEmptyAList.java b/Examples/10-4-Alist-v5-BSTs/NonEmptyAList.java new file mode 100644 index 0000000..6e85a96 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/NonEmptyAList.java @@ -0,0 +1,84 @@ +// The object constructed by NonEmptyAlist(k,v,left,right) represents an +// interior node of a binary search tree, mapping k to v with left and +// right as the subtrees. + +class NonEmptyAList,V> implements AList { + + private K key; // key for this entry in the AList + private V val; // val for this entry in the AList + private AList left; // the entries with keys < this key + private AList right; // the entries with keys > this key + + NonEmptyAList (K key, V val, AList left, AList right) { + this.key = key; + this.val = val; + this.left = left; + this.right = right; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + // Be smart about duplicate keys. + // New keys are eventually inserted at the leaves + + public AList extend (K newKey, V val) { + if (newKey.equals(this.key)) + return new NonEmptyAList + (this.key, val, left, right); + if (newKey.compareTo(this.key) < 0) + return new NonEmptyAList + (this.key, this.val, + left.extend(newKey,val), + right); + else + return new NonEmptyAList + (this.key, this.val, + left, + right.extend(newKey,val)); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + if (key.equals (this.key)) + return true; + else if (key.compareTo(this.key) < 0) + return left.contains(key); + else + return right.contains(key); + + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else if (key.compareTo(this.key) < 0) + return left.lookup(key); + else return right.lookup(key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + // public String toString() { + // return ("[" + + // left.toString() + // + (this.key.toString()) + // + ":" + (this.val.toString()) + // + right.toString() + // + "]"); + // } + + public String toString() { + return ("(" + (this.key.toString()) + ":" + (this.val.toString()) + ")" + + "[" + + left.toString() + + "," + + right.toString() + + "]" + ); + } + +} diff --git a/Examples/10-4-Alist-v5-BSTs/README b/Examples/10-4-Alist-v5-BSTs/README new file mode 100644 index 0000000..44c7230 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/README @@ -0,0 +1,5 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist +10-2: Adds singleton pattern +10-3 ADDS: keep keys in order diff --git a/Examples/10-4-Alist-v5-BSTs/Tests.java b/Examples/10-4-Alist-v5-BSTs/Tests.java new file mode 100644 index 0000000..820eaf0 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/Tests.java @@ -0,0 +1,114 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + AList a5 = a4.extend ("u", 5); + + System.out.println("a0: " + a0.toString()); + System.out.println("a1: " + a1.toString()); + System.out.println("a2: " + a2.toString()); + System.out.println("a3: " + a3.toString()); + System.out.println("a4: " + a4.toString()); + System.out.println("a5: " + a5.toString()); + + checkTrue(a1.contains("x"), "a1 should contain x"); + + checkTrue(a2.contains("x"), "a2 should contain x"); + checkTrue(a2.contains("y"), "a2 should contain y"); + + checkTrue(a3.contains("x"), "a3 should contain x"); + checkTrue(a3.contains("y"), "a3 should contain y"); + checkTrue(a3.contains("z"), "a3 should contain z"); + + checkTrue(a4.lookup("x")==1, "a4(z) should equal 1"); + + checkTrue(a4.contains("x"), "a4 should contain x (first test)"); + checkTrue(a4.contains("y"), "a4 ahould contain y"); + checkTrue(a4.contains("z"), "a4 should contain z"); + checkFalse(a4.contains("u"), "a4 should contain u"); + + checkTrue(a4.lookup("y")== 4, "a4(y) should equal 4"); + checkTrue(a4.lookup("z") == 3, "a4(z) should equal 3"); + + System.err.println("end of a4 tests"); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + AList c0 = ALists.empty(); + checkFalse (c0.contains ("x"), "c0 should not contain x"); + AList c1 = c0.extend("x",11); + checkTrue (c1.lookup("x") == 11, "c1(x) should equal 11"); + AList c2 = c1.extend("x",22); + checkTrue (c1.lookup("x") == 11, "c1(x) should still equal 11"); + checkTrue (c2.lookup("x") == 22, "c2(x) should equal 22"); + + checkFalse (a0.contains ("x"), "a0 should not contain x"); + checkTrue (a3.contains ("z"), "a3 should contain z"); + checkTrue (a4.contains ("x"), "a4 should contain x"); + checkFalse (a4.contains ("b"), "a4 should contain x"); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1, "a1(x) should equal 1"); + checkTrue (a2.lookup ("y") == 2, "a2(x) should equal 2"); + checkTrue (a4.lookup ("x") == 1, "a4(x) should equal 1"); + checkTrue (a4.lookup ("y") == 4, "a4(y) should equal 4"); + checkTrue (a4.lookup ("z") == 3, "a4(z) should equal 3"); + + checkTrue (b2.lookup ("x") == 1, "b2(x) should equal 1"); + checkTrue (b2.lookup ("y") == 2, "b2(y) should equal 2"); + checkTrue (b4.lookup ("x") == 33, "b4(x) should equal 33"); + checkTrue (b4.lookup ("y") == 44, "b4(y) should equal 44"); + checkTrue (b4.lookup ("b") == 22, "b4(b) should equal 22"); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + // System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-4-IMapV2/IMap.java b/Examples/10-4-IMapV2/IMap.java deleted file mode 100644 index 509f0be..0000000 --- a/Examples/10-4-IMapV2/IMap.java +++ /dev/null @@ -1,20 +0,0 @@ -// An IMap is an object of any class that implements IMap. -// -// Interpretation: An IMap represents an immutable finite function -// from keys to values. -// -// IMap extends java.util.Map, so an IMap can be used -// as an unmodifiable Map. - -import java.util.Map; - -interface IMap extends Map { - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - // - // Invariant: the key cannot be null. - - IMap extend (K key, V value); -} diff --git a/Examples/10-4-IMapV2/IMapBST.java b/Examples/10-4-IMapV2/IMapBST.java deleted file mode 100644 index 4fc4830..0000000 --- a/Examples/10-4-IMapV2/IMapBST.java +++ /dev/null @@ -1,192 +0,0 @@ -// Constructor templates for IMapBST: -// -// IMapBST.empty(c) -// Interpretation: -// c is the comparator to be used by the map -// -// this.make (k, v, left, right) -// Interpretation: -// k and v are the key and value to be used at the root -// left is the left subtree -// right is the right subtree -// Where: -// k is distinct from all keys in the left and right subtrees -// k is greater than all keys in the left subtree -// k is less than all keys in the right subtree -// the left and right subtrees obey those invariants, recursively - -import java.util.List; -import java.util.ArrayList; - -import java.util.Iterator; - -import java.util.Comparator; - -// Strategy: extends SortedIMapBase - -abstract class IMapBST extends SortedIMapBase { - - private Comparator cmp; // the comparator for this map - - IMapBST (Comparator cmp) { - this.cmp = cmp; - } - - // Returns an empty map with the given comparator. - - static IMapBST empty (Comparator cmp) { - return new IMapEmptyBST (cmp); - } - - // Returns an non-empty map with the given components. - // Invariants: - // key does not occur in the left or right subtrees - // key is greater than all keys in left subtree - // key is less than all keys in right subtree - // the left and right subtrees obey those invariants, recursively - - IMapBST make (K key, V val, - IMapBST left, - IMapBST right) { - return new IMapNonEmptyBST (key, val, left, right); - } - - // abstract methods listed by SortedMap - - public Comparator comparator () { return cmp; } - - // Returns an iterator for the keys of this IMap. - - protected Iterator keyIterator() { - List lst = new ArrayList(); - this.addKeys (lst); - return lst.iterator(); - } - - // Abstract help methods. - - // Adds the keys of this tree, in order, to the given list. - - abstract void addKeys (List lst); -} - -class IMapEmptyBST extends IMapBST { - - // Java constructor - - IMapEmptyBST (Comparator cmp) { - super(cmp); - } - - // abstract methods listed by Map - - public int size () { return 0; } - - // abstract methods listed by IMap - - public IMap extend (K key, V val) { - return this.make (key, val, this, this); - } - - // abstract methods declared by IMapBase - - // Returns true iff this map has a mapping for the given key. - - protected boolean hasKey (K key) { return false; } - - // Returns the value associated with the given key. - - protected V getVal (K key) { - throw new RuntimeException ("getVal called with empty map: " + key); - } - - // Abstract help methods. - - // Adds the keys of this tree, in order, to the given list. - - void addKeys (List lst) { } -} - -class IMapNonEmptyBST extends IMapBST { - - private K key; // the key at the root of this tree - private V val; // the value associated with that key - private IMapBST left; // the left subtree of this tree - private IMapBST right; // the right subtree of this tree - - private int theSize; // the size of this tree - - // Java constructor - // Invariant: the left and right subtrees have the same comparator. - - IMapNonEmptyBST (K key, V val, IMapBST left, IMapBST right) { - super(left.comparator()); - this.key = key; - this.val = val; - this.left = left; - this.right = right; - this.theSize = 1 + left.size() + right.size(); - } - - // abstract methods listed by Map - - public int size () { return theSize; } - - // abstract methods listed by IMap - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - // - // Invariant: the key cannot be null. - - public IMap extend (K key, V val) { - int cresult = this.comparator().compare (key, this.key); - if (cresult == 0) - return this.make (key, val, left, right); - else if (cresult < 0) - return this.make (this.key, this.val, - (IMapBST) this.left.extend (key, val), - this.right); - else - return this.make (this.key, this.val, - this.left, - (IMapBST) this.right.extend (key, val)); - } - - // abstract methods declared by IMapBase - - // Returns true iff this map has a mapping for the given key. - - protected boolean hasKey (K key) { - int cresult = this.comparator().compare (key, this.key); - if (cresult == 0) - return true; - else if (cresult < 0) - return this.left.hasKey(key); - else - return this.right.hasKey(key); - } - - // Returns the value associated with the given key. - - protected V getVal (K key) { - int cresult = this.comparator().compare (key, this.key); - if (cresult == 0) - return this.val; - else if (cresult < 0) - return this.left.getVal(key); - else - return this.right.getVal(key); - } - - // Abstract help methods. - - // Adds the keys of this tree, in order, to the given list. - - void addKeys (List lst) { - this.left.addKeys (lst); - lst.add (this.key); - this.right.addKeys (lst); - } -} diff --git a/Examples/10-4-IMapV2/IMapBase.java b/Examples/10-4-IMapV2/IMapBase.java deleted file mode 100644 index d571f3c..0000000 --- a/Examples/10-4-IMapV2/IMapBase.java +++ /dev/null @@ -1,197 +0,0 @@ -// Abstract base class for classes that implement IMap or SortedIMap. -// -// To define a class that implements IMap: -// make that class a subclass of this base class -// within that class, define the following abstract methods: -// public IMap extend(K key, V value) -// protected boolean hasKey(K key) -// protected V getVal(K key) -// protected Iterator keyIterator() -// within that class, override the following methods: -// public int size() -// -// To define a class that implements SortedIMap: -// make that class a subclass of SortedIMapBase -// define or override the methods listed above -// define comparator() - -import java.util.Map; -import java.util.Map.Entry; -import java.util.AbstractMap; -import java.util.AbstractMap.SimpleImmutableEntry; - -import java.util.Set; -import java.util.AbstractSet; - -import java.util.List; -import java.util.ArrayList; - -import java.util.Iterator; - -// Strategy, quoted from the documentation for AbstractMap: -// -// To implement an unmodifiable map, the programmer needs only to -// extend [the AbstractMap] class and provide an implementation -// for the entrySet method, which returns a set-view of the map's -// mappings. Typically, the returned set will, in turn, be -// implemented atop AbstractSet. This set should not support the -// add or remove methods, and its iterator should not support the -// remove method. - -abstract class IMapBase extends AbstractMap implements IMap { - - // Java constructor - - protected IMapBase () { } - - // public methods listed by IMap interface - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - - public abstract IMap extend (K key, V value); - - // public methods listed by Map interface - - // Returns true iff this map contains a mapping for the given key. - - @Override - @SuppressWarnings("unchecked") - public boolean containsKey (Object x) { - if (x == null) { - String nullMsg = "null values aren't allowed by IMap"; - throw new NullPointerException (nullMsg); - } - else { - K key = (K) x; - return hasKey (key); - } - } - - // Returns the value associated with the given key, - // or null if the key is not contained within the map. - - @Override - @SuppressWarnings("unchecked") - public V get (Object x) { - if (containsKey (x)) { - K key = (K) x; - return getVal (key); - } - else return null; - } - - // Returns true iff this map contains no key/value mappings. - - @Override - public boolean isEmpty () { - return size() == 0; - } - - // Returns a set of the key/value pairs in this Map. - - public Set> entrySet () { - Iterator it = keyIterator(); - List> entries = new ArrayList>(); - while (it.hasNext()) { - K key = it.next(); - V value = getVal (key); - Entry entry = new SimpleImmutableEntry (key, value); - entries.add (entry); - } - return new ListSet (entries); - } - - // all other public methods are defined by AbstractMap - - // overriding the usual triumvirate - - // Unsorted maps are equal if they have equal keys and values. - // Unsorted maps are never considered equal to sorted maps - // because the existence of a comparator method creates an - // observable difference, and the comparator might not be - // consistent with the equals method on keys. - - @SuppressWarnings("unchecked") - public boolean equals (Object x) { - if (x instanceof IMapBase) { - IMapBase m = (IMapBase) x; - if (x instanceof SortedIMapBase) - return false; - else if (this.size() != m.size()) - return false; - else { - Iterator it = keyIterator(); - while (it.hasNext()) { - K key = it.next(); - if (m.hasKey(key) && - this.getVal(key).equals(m.getVal(key))) - ; // do nothing - else return false; - } - return true; - } - } - else return false; - } - - // The hash code of an unsorted map cannot depend on the order - // in which keys are generated by the iterator, so we can't - // cut this computation off early. - - public int hashCode () { - Iterator it = keyIterator(); - int result = 434937289; - while (it.hasNext()) { - K key = it.next(); - V val = getVal (key); - int keyHash = key.hashCode(); - int valHash = val.hashCode(); - result = result + 1232250328 * keyHash - 1436654170 * valHash; - } - return result; - } - - public String toString () { - System.out.println (super.toString()); - return "an IMap of size " + size() + " and hash " + hashCode(); - } - - // abstract help methods - - // Returns true iff this map has a mapping for the given key. - - protected abstract boolean hasKey (K key); - - // Returns the value associated with the given key. - - protected abstract V getVal (K key); - - // Returns an iterator for the keys of this IMap. - - protected abstract Iterator keyIterator(); -} - -class ListSet extends AbstractSet> { - - List> entries; - - // Java constructors - - ListSet (List> entries) { - this.entries = entries; - } - - // public methods - - // Returns an Iterator for the entries in this set. - - public Iterator> iterator () { - return entries.iterator (); - } - - // Returns the size of this set. - - public int size () { return entries.size(); } -} diff --git a/Examples/10-4-IMapV2/IMapList.java b/Examples/10-4-IMapV2/IMapList.java deleted file mode 100644 index e6e5a5a..0000000 --- a/Examples/10-4-IMapV2/IMapList.java +++ /dev/null @@ -1,114 +0,0 @@ -// Constructor templates for IMapList: -// new IMapList (rktList) -// new IMapList () -// Interpretation: -// rktList is a RacketList -// containing the key/value pairs of the IMap -// where no key is the key for two different key/value pairs -// if rktList is omitted, creates an empty map - -import java.util.Map; -import java.util.Map.Entry; -import java.util.AbstractMap.SimpleImmutableEntry; - -import java.util.List; -import java.util.ArrayList; - -import java.util.Iterator; - -// Strategy: extends IMapBase - -final class IMapList extends IMapBase { - - RacketList> entries; // set of key/value pairs - - // Java constructors - - IMapList () { - this.entries = RacketLists.empty(); - } - - IMapList (RacketList> entries) { - this.entries = entries; - } - - // abstract methods listed by Map interface - - public int size () { - return RacketLists.length (entries); - } - - // abstract methods listed by IMap interface - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - - public IMap extend (K key, V value) { - Entry entry = new SimpleImmutableEntry (key, value); - return new IMapList (extended (entries, entry)); - } - - // abstract methods declared in IMapBase - - // Returns true iff this map has a mapping for the given key. - - protected boolean hasKey (K key) { - RacketList> lst = entries; - while (! (lst.isEmpty())) { - if (lst.first().getKey().equals (key)) - return true; - lst = lst.rest(); - } - return false; - } - - // Returns the value associated with the given key. - - protected V getVal (K key) { - RacketList> lst = entries; - while (! (lst.isEmpty())) { - if (lst.first().getKey().equals (key)) - return lst.first().getValue(); - lst = lst.rest(); - } - String badKeyMsg = "key not found in IMap: "; - throw new IllegalArgumentException(badKeyMsg + key); - } - - // Returns an iterator for the keys of this IMap. - - protected Iterator keyIterator() { - RacketList> lst = entries; - List keys = new ArrayList(); - while (! (lst.isEmpty())) { - keys.add (lst.first().getKey()); - lst = lst.rest(); - } - return keys.iterator(); - } - - // all other public methods are defined by AbstractMap - - // private help methods - - // Given a RacketList of entries and an entry with key k, - // returns a RacketList in which the given entry replaces - // any entry with key k or, if the given RacketList of entries - // contains no entry with key k, returns a RacketList with - // the given entry added to it. - // - // This method has no side effects. - - private RacketList> extended (RacketList> entries, - Entry entry) { - if (entries.isEmpty()) { - return entries.cons (entry); - } - if (entries.first().getKey().equals (entry.getKey())) { - return entries.rest().cons (entry); - } - else - return extended (entries.rest(), entry).cons (entries.first()); - } -} diff --git a/Examples/10-4-IMapV2/IMaps.java b/Examples/10-4-IMapV2/IMaps.java deleted file mode 100644 index ff0e36e..0000000 --- a/Examples/10-4-IMapV2/IMaps.java +++ /dev/null @@ -1,102 +0,0 @@ -// The IMaps class defines static methods for the IMap type. -// In particular, it defines static factory methods for creating -// empty maps of the IMap type. - -import java.util.Iterator; - -import java.util.Comparator; - -class IMaps { - - private static IMap theEmptyIMap = new IMapList(); - - // static factory methods for creating an empty IMap - - @SuppressWarnings("unchecked") - public static IMap empty () { - return (IMap) theEmptyIMap; - } - - @SuppressWarnings("unchecked") - public static SortedIMap empty (Comparator c) { - return IMapBST.empty(c); - } - - // main method for testing - - public static void main (String[] args) { - IMapTests.main (args); - } -} - -// Tests for IMap objects. - -class IMapTests { - - public static void main (String[] args) { - mainUnsorted(args); - mainSorted(args); - System.out.println ("IMap tests passed."); - } - - // Tests unsorted maps. - - private static void mainUnsorted (String[] args) { - IMap m0 = IMaps.empty(); - IMap m00 = IMaps.empty(); - mainCommon (m0, m00); - } - - // Tests sorted maps. - - private static void mainSorted (String[] args) { - Comparator cmp - = new Comparator() { - public int compare (Integer i, Integer j) { - return Integer.compare (i.intValue(), j.intValue()); - } - }; - IMap m0 = IMaps.empty(cmp); - IMap m00 = IMaps.empty(cmp); - mainCommon (m0, m00); - } - - // Works for both sorted and unsorted maps. - - private static void mainCommon (IMap m0, - IMap m00) { - IMap m1 = m0.extend (1, "one"); - IMap m2 = m0.extend (2, "two"); - IMap m3 = m0.extend (3, "three"); - IMap m4 = m0.extend (4, "four"); - IMap m5 = m0.extend (5, "five"); - IMap m6 = m0.extend (6, "six"); - IMap m7 = m0.extend (7, "seven"); - IMap m8 = m0.extend (8, "eight"); - IMap m9 = m0.extend (9, "nine"); - - IMap m03 = m9.extend (3, "drei"); - IMap m10 = m03.extend (10, "zehn"); - - assert ! m0.containsKey(1); - assert m9.containsKey(4); - assert ! m9.containsKey(10); - - assert m9.get(9).equals("nine"); - assert m9.get(3).equals("three"); - assert m9.get(1).equals("one"); - - assert m10.get(9).equals("nine"); - assert m10.get(3).equals("drei"); - assert m10.get(1).equals("one"); - - assert m0.isEmpty(); - assert ! m1.isEmpty(); - - assert m0.size() == 0; - assert m1.size() == 1; - assert m9.size() == 9; - assert m03.size() == 9; - assert m10.size() == 10; - } -} diff --git a/Examples/10-4-IMapV2/SortedIMap.java b/Examples/10-4-IMapV2/SortedIMap.java deleted file mode 100644 index 321942c..0000000 --- a/Examples/10-4-IMapV2/SortedIMap.java +++ /dev/null @@ -1,13 +0,0 @@ -// A SortedIMap is an object of any class that implements SortedIMap. -// -// Interpretation: A SortedIMap represents an immutable finite function -// from keys to values, together with a comparator that defines a total -// ordering on the keys. -// -// Constraint: the extend method of a SortedIMap must return -// a SortedIMap. - -import java.util.SortedMap; - -interface SortedIMap extends SortedMap, IMap { -} diff --git a/Examples/10-4-IMapV2/SortedIMapBase.java b/Examples/10-4-IMapV2/SortedIMapBase.java deleted file mode 100644 index 33f8abf..0000000 --- a/Examples/10-4-IMapV2/SortedIMapBase.java +++ /dev/null @@ -1,188 +0,0 @@ -// Abstract base class for classes that implement SortedIMap. -// -// To define a class that implements SortedIMap: -// make that class a subclass of SortedIMapBase -// within that class, define the following abstract methods: -// public Comparator comparator() -// public IMap extend(K key, V value) -// protected boolean hasKey(K key) -// protected V getVal(K key) -// protected Iterator keyIterator() -// within that class, override the following methods: -// public int size() - -import java.util.Map; -import java.util.Map.Entry; -import java.util.AbstractMap; -import java.util.AbstractMap.SimpleEntry; -import java.util.AbstractMap.SimpleImmutableEntry; - -import java.util.SortedMap; - -import java.util.Set; -import java.util.AbstractSet; - -import java.util.List; -import java.util.ArrayList; - -import java.util.Iterator; - -import java.util.Comparator; - -import java.util.NoSuchElementException; - -// Strategy: extend IMapBase and add the necessary methods. - -abstract class SortedIMapBase - extends IMapBase - implements SortedIMap { - - // Java constructor - - protected SortedIMapBase () { } - - // public methods listed by SortedMap interface - - // Returns the comparator used to sort the keys in this map. - - public abstract Comparator comparator(); - - // public methods listed by the SortedMap interface - - // Returns the first (lowest) key in this map. - - public K firstKey() { - if (this.isEmpty()) - throw new NoSuchElementException (emptySortedMapMsg); - else - return this.keyIterator().next(); - } - - // Returns the last (highest) key in this map. - - public K lastKey() { - if (this.isEmpty()) - throw new NoSuchElementException (emptySortedMapMsg); - else { - Iterator it = this.keyIterator(); - K result = it.next(); - while (it.hasNext()) - result = it.next(); - return result; - } - } - - private static final String emptySortedMapMsg - = "firstKey or lastKey called on empty SortedIMap"; - - // Returns a view of the portion of this map whose keys are - // strictly less than toKey. - - public SortedMap headMap (K toKey) { - Comparator c = this.comparator(); - Iterator it = this.keyIterator(); - SortedIMap result = IMaps.empty(c); - while (it.hasNext()) { - K key = it.next(); - V val = this.getVal(key); - if (c.compare (key, toKey) < 0) - result = (SortedIMap) result.extend (key, val); - else - return result; - } - return result; - } - - // Returns a view of the portion of this map whose keys range - // from fromKey, inclusive, to toKey, exclusive. - - public SortedMap subMap (K fromKey, K toKey) { - Comparator c = this.comparator(); - Iterator it = this.keyIterator(); - SortedIMap result = IMaps.empty(c); - while (it.hasNext()) { - K key = it.next(); - V val = this.getVal(key); - if (c.compare (key, fromKey) < 0) - ; // do nothing - else if (c.compare (key, toKey) < 0) - result = (SortedIMap) result.extend (key, val); - else - return result; - } - return result; - } - - // Returns a view of the portion of this map whose keys are - // greater than or equal to fromKey. - - public SortedMap tailMap (K fromKey) { - Comparator c = this.comparator(); - Iterator it = this.keyIterator(); - SortedIMap result = IMaps.empty(c); - while (it.hasNext()) { - K key = it.next(); - V val = this.getVal(key); - if (c.compare (key, fromKey) < 0) - ; // do nothing - else - result = (SortedIMap) result.extend (key, val); - } - return result; - } - - // all other public methods are defined by IMapBase - - // overriding the usual triumvirate - - // Sorted maps are equal if they have equal keys and values. - // Sorted maps are never considered equal to unsorted maps - // because the existence of a comparator method creates an - // observable difference, and the comparator might not be - // consistent with the equals method on keys. - - @SuppressWarnings("unchecked") - public boolean equals (Object x) { - if (x instanceof SortedIMapBase) { - SortedIMapBase m = (SortedIMapBase) x; - if (! (this.comparator().equals(m.comparator()))) - return false; - else if (this.size() != m.size()) - return false; - else { - Iterator it = keyIterator(); - while (it.hasNext()) { - K key = it.next(); - if (m.hasKey(key) && - this.getVal(key).equals(m.getVal(key))) - ; // do nothing - else return false; - } - return true; - } - } - else return false; - } - - // The hash code of a sorted map can depend on the order - // in which keys are generated by the iterator, but this - // definition doesn't take advantage of that. - - public int hashCode () { - Iterator it = keyIterator(); - int result = 2005052521; - while (it.hasNext()) { - K key = it.next(); - V val = getVal (key); - int keyHash = key.hashCode(); - int valHash = val.hashCode(); - result = result - 978278598 * keyHash + 1048370044 * valHash; - } - return result; - } - - public String toString () { - System.out.println (super.toString()); - return "a SortedIMap of size " + size() + " and hash " + hashCode(); - } -} diff --git a/Examples/10-4-stateful-wall.rkt b/Examples/10-4-stateful-wall.rkt deleted file mode 100644 index 2becd09..0000000 --- a/Examples/10-4-stateful-wall.rkt +++ /dev/null @@ -1,530 +0,0 @@ -#lang racket - -;; 10-4-stateful-wall.rkt - -;; Like 10-2, but the wall will be stateful - -;; the world will be an object with exactly two widgets: -;; a ball and a wall. - -;; In this version, the wall is draggable, but the ball is not. -;; The ball should bounce off the wall. - -;; The ball is told about the wall when it's created - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 8) - -(define INITIAL-WALL-POSITION 300) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; A World is an object of any class that implements World<%> - -(define World<%> - (interface () - - ; -> World - ; GIVEN: no arguments - ; RETURNS: the state of the world at the next tick - after-tick - - ; Integer Integer MouseEvent-> World - ; GIVEN: a location - ; RETURNS: the state of the world that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> World - ; GIVEN: a key event - ; RETURNS: the state of the world that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - )) - -;; A Widget is an object of any class that implements Widget<%> - - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; In 10-4, the wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -(define SWall<%> - (interface (SWidget<%>) - - ; -> Int - ; RETURNS: the x-position of the wall - get-pos - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a stateful wall, and a ball that knows about -;; the wall. -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new Ball% [w the-wall]))) - (make-world-state - (list the-ball) - (list the-wall)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the final state of the world -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (send w after-tick)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (send w after-key-event kev))) - (on-mouse - (lambda (w mx my mev) - (send w after-mouse-event mx my mev))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The World% class. -;; Like World% in 10-2, but supports SWidgets as well as Widgets. - -; ListOfWidget ListOfSWidget -> World -(define (make-world-state objs sobjs) - (new World% [objs objs][sobjs sobjs])) - -(define World% - (class* object% (World<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - ;; process-widgets : ((Widget -> Widget) && (SWidget -> Void)) -> World - ;; An abstraction to pass messages to both Widgets and SWidgets. - ;; apply the fn to both the objs and the sobjs, and return a new - ;; World% with new values of the objs, and with sobjs updated - ;; appropriately. - ;; This has a contract that is not directly expressible in our - ;; usual language of contracts. The notation we've written means - ;; that fn must satisfy the contracts - ;; (Widget -> Widget) AND (SWidget -> Void). - (define (process-widgets fn) - (new World% - [objs (map fn objs)] - [sobjs (begin - (for-each fn sobjs) - sobjs)])) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - #;(define/public (after-tick) - (new World% - [objs (map - (lambda (obj) (send obj after-tick)) - objs)] - [sobjs (begin - (for-each - (lambda (obj) (send obj after-tick)) - sobjs) - sobjs)])) - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append sobjs objs))) - - ;; after-key-event : KeyEvent -> World - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> World - ;; STRATGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The Ball% class -;; (same as 10-2-1) - -;; A Ball is a (new Ball% [x Int][y Int][speed Int][w Wall]) -;; w is required; all others have default values. - -(define Ball% - (class* object% (Widget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - (super-new) - - ;; after-tick : -> Ball - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? this - (new Ball% - [x (next-x-pos)] - [y y] - [speed (next-speed)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: ask the wall for its position and use that to - ;; calculate the upper bound for the ball's x position - - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- (send w get-pos) radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - ;; EXAMPLES: - ;; (limit-value 10 20 30) = 20 - ;; (limit-value 10 5 30) = 10 - ;; (limit-value 10 100 30) = 30 - - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will be at its limit, negate the - ;; velocity, otherwise return it unchanged - (define (next-speed) - (if (or - (= (next-x-pos) radius) - (= (next-x-pos) (- (send w get-pos) radius))) - (- speed) - speed)) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Ball - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)] - [w w]) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Ball - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? false] - [saved-mx 127] - [saved-my 98] ; the invariant says that if selected? is - ; false, you can put anything here. - [w w]) - this)) - - ; after-drag : Integer Integer -> Ball - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Ball% - [x (- mx saved-mx)] - [y (- my saved-my)] - [speed speed] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]) - this)) - - ;; the ball ignores key events - (define/public (after-key-event kev) this) - - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class. Implements SWall<%>, not Wall<%>. - - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - ;; relative to the wall position - (init-field [saved-mx 0]) - - (super-new) - - ;; the extra behavior for Wall<%> - (define/public (get-pos) pos) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos)) - ;; this - ) - 42)) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (set! pos (- mx saved-mx)) - 38)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/10-5-Alist-v6-stateful/AList.java b/Examples/10-5-Alist-v6-stateful/AList.java new file mode 100644 index 0000000..c4b809e --- /dev/null +++ b/Examples/10-5-Alist-v6-stateful/AList.java @@ -0,0 +1,46 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// *** NOTICE THAT ALL THESE EQUALITIES ARE OF VALUES AND BOOLEANS, +// *** NOT OF ALISTS THEMSELVES. THEY TALK ABOUT THE **BEHAVIOR** OF +// *** ALISTS. + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList,V> { + + // extends this AList by associating the given key with the given value. + + void extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-5-Alist-v6-stateful/ALists.java b/Examples/10-5-Alist-v6-stateful/ALists.java new file mode 100644 index 0000000..009e745 --- /dev/null +++ b/Examples/10-5-Alist-v6-stateful/ALists.java @@ -0,0 +1,36 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class ALists { + + private static AList theEmptyAList = new Header(); + + // static factory method for creating an empty AList + + @SuppressWarnings("unchecked") + public static ,V> AList empty () { + return (AList) theEmptyAList; + } + + + // // this generates a new EmptyAList object every time it is called. + // // public static AList empty () { + // public static ,V> AList empty () { + // return new EmptyAList (); + // } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-5-Alist-v6-stateful/EmptyAlist.java b/Examples/10-5-Alist-v6-stateful/EmptyAlist.java new file mode 100644 index 0000000..71264dd --- /dev/null +++ b/Examples/10-5-Alist-v6-stateful/EmptyAlist.java @@ -0,0 +1,60 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +// The representation is a header node root field, initially null, which will +// point at the eventual real root of the binary search tree. + +import java.util.NoSuchElementException; + + + +class Header,V> implements AList { + + AList root = null; + + // Returns an association list like this one + // except the given key is associated with the given value. + + // the first time, installs a new interior node as the value of + // root. This node will be the "real" root of the tree. + // all subequent accessess are delegated to the root. + + public void extend (K key, V val) { + if (root == null) { + root = new NonEmptyAList (key, val, null, null); + } + else root.extend(key,val); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + if (root == null) { return false; } + else {return root.contains(key);} + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (root == null) { + throw new NoSuchElementException ("key not found: " + key);} + else return root.lookup(key); + } + + + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString () { + if (root == null) {return "*";} + else {return "*"+root.toString();} + } + +} diff --git a/Examples/10-5-Alist-v6-stateful/NonEmptyAList.java b/Examples/10-5-Alist-v6-stateful/NonEmptyAList.java new file mode 100644 index 0000000..e090290 --- /dev/null +++ b/Examples/10-5-Alist-v6-stateful/NonEmptyAList.java @@ -0,0 +1,84 @@ +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +// We implement this as a binary search tree. + +class NonEmptyAList,V> implements AList { + + private K key; // key for this entry in the AList + private V val; // val for this entry in the AList + private AList left; // the entries with keys < this key + private AList right; // the entries with keys > this key + + NonEmptyAList (K key, V val, AList left, AList right) { + this.key = key; + this.val = val; + this.left = left; + this.right = right; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + // Be smart about duplicate keys. + // New keys are eventually inserted at the leaves + + public void extend (K newKey, V newVal) { + if (newKey.equals(this.key)) + this.val = newVal; + else if (newKey.compareTo(this.key) < 0) { + if (left == null) { + left = new NonEmptyAList(newKey, newVal, null, null); + } + else left.extend(newKey,val); + } + else {if (right == null) { + right = new NonEmptyAList(newKey, newVal, null, null); + } + else right.extend(newKey,val); + } + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K otherKey) { + if (otherKey.equals (this.key)) + return true; + else if (otherKey.compareTo(this.key) < 0) + return (left != null && left.contains(otherKey)); + else + return (right != null && right.contains(otherKey)); + + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + // this code is wrong, because it doesn't check for null left or null right. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else if (key.compareTo(this.key) < 0) + return left.lookup(key); + else return right.lookup(key); + } + + private String maybeToString (AList x) { + if (x == null) {return "%";} + else {return x.toString();} + } + + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString() { + return ("[" + + maybeToString(left) + + (this.key.toString()) + + ":" + (this.val.toString()) + + maybeToString(right) + + "]"); + } + +} diff --git a/Examples/10-5-Alist-v6-stateful/README b/Examples/10-5-Alist-v6-stateful/README new file mode 100644 index 0000000..44c7230 --- /dev/null +++ b/Examples/10-5-Alist-v6-stateful/README @@ -0,0 +1,5 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist +10-2: Adds singleton pattern +10-3 ADDS: keep keys in order diff --git a/Examples/10-5-Alist-v6-stateful/Tests.java b/Examples/10-5-Alist-v6-stateful/Tests.java new file mode 100644 index 0000000..bd7ab51 --- /dev/null +++ b/Examples/10-5-Alist-v6-stateful/Tests.java @@ -0,0 +1,120 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + a0.extend ("x", 1); + System.out.println("a0: " + a0.toString()); + a0.extend ("y", 2); + System.out.println("a0: " + a0.toString()); + a0.extend ("z", 3); + System.out.println("a0: " + a0.toString()); + a0.extend ("y", 4); + System.out.println("a0: " + a0.toString()); + a0.extend ("u", 5); + System.out.println("a0: " + a0.toString()); + a0.extend ("v", 6); + System.out.println("a0: " + a0.toString()); + + + checkTrue(a0.contains("x"), "a0 should contain x"); + checkTrue(a0.contains("y"), "a0 should contain y"); + checkTrue(a0.contains("z"), "a0 should contain z"); + checkTrue(a0.contains("u"), "a0 should contain u"); + checkFalse(a0.contains("w"), "a0 should not contain w"); + + + // checkTrue(a2.contains("x"), "a2 should contain x"); + // checkTrue(a2.contains("y"), "a2 should contain y"); + + // checkTrue(a3.contains("x"), "a3 should contain x"); + // checkTrue(a3.contains("y"), "a3 should contain y"); + // checkTrue(a3.contains("z"), "a3 should contain z"); + + // checkTrue(a4.lookup("x")==1, "a4(z) should equal 1"); + + // checkTrue(a4.contains("x"), "a4 should contain x (first test)"); + // checkTrue(a4.contains("y"), "a4 ahould contain y"); + // checkTrue(a4.contains("z"), "a4 should contain z"); + // checkFalse(a4.contains("u"), "a4 should contain u"); + + // checkTrue(a4.lookup("y")== 4, "a4(y) should equal 4"); + // checkTrue(a4.lookup("z") == 3, "a4(z) should equal 3"); + + // System.err.println("end of a4 tests"); + + // AList b2 = a2.extend ("b", 22); + // AList b3 = b2.extend ("x", 33); + // AList b4 = b3.extend ("y", 44); + + // AList c0 = ALists.empty(); + // checkFalse (c0.contains ("x"), "c0 should not contain x"); + // AList c1 = c0.extend("x",11); + // checkTrue (c1.lookup("x") == 11, "c1(x) should equal 11"); + // AList c2 = c1.extend("x",22); + // checkTrue (c1.lookup("x") == 11, "c1(x) should still equal 11"); + // checkTrue (c2.lookup("x") == 22, "c2(x) should equal 22"); + + // checkFalse (a0.contains ("x"), "a0 should not contain x"); + // checkTrue (a3.contains ("z"), "a3 should contain z"); + // checkTrue (a4.contains ("x"), "a4 should contain x"); + // checkFalse (a4.contains ("b"), "a4 should contain x"); + + // checkTrue (b2.contains ("b")); + // checkTrue (b2.contains ("x")); + // checkTrue (b2.contains ("y")); + // checkFalse (b2.contains ("z")); + + // checkTrue (a1.lookup ("x") == 1, "a1(x) should equal 1"); + // checkTrue (a2.lookup ("y") == 2, "a2(x) should equal 2"); + // checkTrue (a4.lookup ("x") == 1, "a4(x) should equal 1"); + // checkTrue (a4.lookup ("y") == 4, "a4(y) should equal 4"); + // checkTrue (a4.lookup ("z") == 3, "a4(z) should equal 3"); + + // checkTrue (b2.lookup ("x") == 1, "b2(x) should equal 1"); + // checkTrue (b2.lookup ("y") == 2, "b2(y) should equal 2"); + // checkTrue (b4.lookup ("x") == 33, "b4(x) should equal 33"); + // checkTrue (b4.lookup ("y") == 44, "b4(y) should equal 44"); + // checkTrue (b4.lookup ("b") == 22, "b4(b) should equal 22"); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + // System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-5-ball-factory.rkt b/Examples/10-5-ball-factory.rkt deleted file mode 100644 index 1f4c30c..0000000 --- a/Examples/10-5-ball-factory.rkt +++ /dev/null @@ -1,562 +0,0 @@ -#lang racket - -;; 10-5-ball-factory - -;; Like 10-4, but with a stateful world and many balls. - -;; Uses a ball factory to move ball creation out of World%. -;; Each ball is told about the wall when it's created. - -;; Balls are not stateful. -;; Balls will be draggable. Selected balls do not move. - -;; The wall is still stateful. - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 8) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: adds the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: adds the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Additional method for SWall: - -(define SWall<%> - (interface (SWidget<%>) - - ; -> Int - ; RETURNS: the x-position of the wall - get-pos - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a wall, a ball, and a factory -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new Ball% [w the-wall])) - (define the-world - (make-sworld (list the-ball) (list the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - (send the-world add-stateful-widget the-factory) - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The SWorld% class. -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append sobjs objs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> World - ;; STRATGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; Constructor template for the BallFactory% class: -;; (new BallFactory% [world SWorld][wall SWall]) - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-widget (new Ball% [w wall]))])) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The Ball% class - -;; Constructor template for Ball%: -;; (new Ball% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define Ball% - (class* object% (Widget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; heli's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - (super-new) - - ;; after-tick : -> Ball - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? this - (new Ball% - [x (next-x-pos)] - [y y] - [speed (next-speed)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: ask the wall for its position and use that to - ;; calculate the upper bound for the ball's x position - - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- (send w get-pos) radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - ;; EXAMPLES: - ;; (limit-value 10 20 30) = 20 - ;; (limit-value 10 5 30) = 10 - ;; (limit-value 10 100 30) = 30 - - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will be at its limit, negate the - ;; velocity, otherwise return it unchanged - (define (next-speed) - (if (or - (= (next-x-pos) radius) - (= (next-x-pos) (- (send w get-pos) radius))) - (- speed) - speed)) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Ball - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)] - [w w]) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Ball - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? false] - [saved-mx 127] - [saved-my 98] ; the invariant says that if selected? is - ; false, you can put anything here. - [w w]) - this)) - - ; after-drag : Integer Integer -> Ball - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Ball% - [x (- mx saved-mx)] - [y (- my saved-my)] - [speed speed] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]) - this)) - - ;; the ball ignores key events - (define/public (after-key-event kev) this) - - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class. Implements SWall<%>, not Wall<%>. - - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - (super-new) - - ;; the extra behavior for Wall<%> - (define/public (get-pos) pos) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (set! pos (- mx saved-mx)) - 38)) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/10-6-push-model.rkt b/Examples/10-6-push-model.rkt deleted file mode 100644 index e53780c..0000000 --- a/Examples/10-6-push-model.rkt +++ /dev/null @@ -1,755 +0,0 @@ -#lang racket - -;; 10-6-push-model - -;; Instead of every ball pulling information from the wall at every -;; tick, the wall notifies each ball, but only when the wall moves. - -;; To do this, each ball will have to have a stable identity, so the -;; wall can send it messages. - - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 30) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;; An SBall is an object of any class that implements SBall<%>. - -;; An SBall is like a Ball, but it is stateful (stable), so its -;; interface extends SWidget<%> rather than Widget<%>. - -;; It has one extra method, which updates the ball's copy of the -;; wall's position. - -(define SBall<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Instead of waiting to be asked, in this version the wall publishes -;; its position to anyone who puts themselves on the list to be -;; notified. It does so by calling the the recipient's -;; 'update-wall-pos' method. - -;; So SWall<%> has a 'register' method, which allows any SBall to sign up -;; for notifications. - -(define SWall<%> - (interface (SWidget<%>) - - ; SBall -> Int - ; GIVEN: An SBall - ; EFFECT: registers the ball to receive position updates from this wall. - ; RETURNS: the x-position of the wall - register - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; 10-6: in the push model, the ball is a stateful widget - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))])) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -;; As of 10-6, the Ball is now a stateful widget - -(define SBall% - (class* object% (SWidget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the ball's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? - this - ;; (new Ball% - ;; [x (next-x-pos)] - ;; [y y] - ;; [speed (next-speed)] - ;; [selected? selected?] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (begin - (set! x (next-x-pos)) - (set! speed (next-speed))))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos ; (send w get-pos) - radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will be at its limit, negate the - ;; velocity, otherwise return it unchanged - (define (next-speed) - (if (or - (= (next-x-pos) radius) - (= (next-x-pos) (- - wall-pos ; was: (send w get-pos) - radius))) - (- speed) - speed)) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? true] - ;; [saved-mx (- mx x)] - ;; [saved-my (- my y)] - ;; [w w]) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? false] - ;; [saved-mx 127] - ;; [saved-my 98] ; the invariant says that if selected? is - ;; ; false, you can put anything here. - ;; [w w]) - (set! selected? false) - 'error-276)) - - ;; In Racket, an 'if' must have two arms. #lang racket also has a - ;; form called 'when', which only requires one arm. You can use - ;; that in your code if you want. - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - ;; (new Ball% - ;; [x (- mx saved-mx)] - ;; [y (- my saved-my)] - ;; [speed speed] - ;; [selected? true] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the ball ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SBall -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (begin - (set! pos (- mx saved-mx)) - ;; NEW in push-model: - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - ;; test methods - ;; don't need deliverables for these. - - ;; in the push model, the wall doesn't have a get-pos method, so we - ;; need to add one for testing. - - (define/public (for-test:get-pos) pos) - - )) - -;; select wall, then drag -(begin-for-test - (local - ;; create a wall - ((define wall1 (new SWall% [pos 200]))) - ;; check to see that it's in the right place - (check-equal? (send wall1 for-test:get-pos) 200) - ;; now select it, then drag it 40 pixels - (send wall1 after-button-down 202 100) - (send wall1 after-drag 242 180) - ;; is the wall in the right place? - (check-equal? (send wall1 for-test:get-pos) 240))) - -;; don't select wall, then drag -(begin-for-test - (local - ;; create a wall - ((define wall1 (new SWall% [pos 200]))) - ;; check to see that it's in the right place - (check-equal? (send wall1 for-test:get-pos) 200) - ;; button-down, but not close enough - (send wall1 after-button-down 208 100) - (send wall1 after-drag 242 180) - ;; wall shouldn't move - (check-equal? (send wall1 for-test:get-pos) 200))) - -;; test bouncing ball -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 170][speed 50][w wall1]))) - - ;; ball created ok? - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -;; we tried this at different starting positions. Here's the first -;; one that failed. -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - -; (check-equal? (send ball1 for-test:next-x) 160) -; (check-equal? (send ball1 for-test:next-speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - )) - -;; position is right, but speed is wrong! Our calculation for speed -;; looks right, but let's check it. We'll add some test methods that -;; just call next-x and next-speed: - - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-x) 160) - (check-equal? (send ball1 for-test:next-speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - )) - -;; Hmm, next-speed returns 50, but when we do after-tick, the speed of -;; the resulting ball is -50. What happened? - -;; Oh no! we did a set! between (next-x) and (next-speed). next-speed -;; depends on x, so when we did the (set! x ...) we changed the value -;; of x, so when we actually computed (next-speed) it was looking at -;; the new value of x, not the old value. - -;; Reversing the order of the set!'s doesn't help, because (next-x) -;; also depends on speed. So we need to compute both values _before_ -;; we do the set!'s. See GP 10.1 for more examples like this. - -;; See 10-6-push-model-fixed for the repaired code. - - diff --git a/Examples/10-7-push-model-fixed.rkt b/Examples/10-7-push-model-fixed.rkt deleted file mode 100644 index 7e20395..0000000 --- a/Examples/10-7-push-model-fixed.rkt +++ /dev/null @@ -1,703 +0,0 @@ -#lang racket - -;; 10-7-push-model-fixed -;; fixes assignment bug in 10-6-push-model - - -;; Instead of every ball pulling information from the wall at every -;; tick, the wall notifies each ball, but only when the wall moves. - -;; To do this, each ball will have to have a stable identity, so the -;; wall can send it messages. - - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 25) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;; An SBall is an object of any class that implements SBall<%>. - -;; An SBall is like a Ball, but it is stateful (stable), so its -;; interface extends SWidget<%> rather than Widget<%>. - -;; It has one extra method, which updates the ball's copy of the -;; wall's position. - -(define SBall<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Instead of waiting to be asked, in this version the wall publishes -;; its position to anyone who puts themselves on the list to be -;; notified. It does so by calling the the recipient's -;; 'update-wall-pos' method. - -;; So SWall<%> has a 'register' method, which allows any SBall to sign up -;; for notifications. - -(define SWall<%> - (interface (SWidget<%>) - - ; SBall -> Int - ; GIVEN: An SBall - ; EFFECT: registers the ball to receive position updates from this wall. - ; RETURNS: the x-position of the wall - register - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; 10-6: in the push model, the ball is a stateful widget - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))])) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -;; As of 10-6, the Ball is now a stateful widget - -(define SBall% - (class* object% (SWidget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the ball's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? - this - ;; (new Ball% - ;; [x (next-x-pos)] - ;; [y y] - ;; [speed (next-speed)] - ;; [selected? selected?] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (let ((x1 (next-x-pos)) - (speed1 (next-speed))) - ;; (next-speed) depends on x, and (next-x-pos) depends on - ;; speed, so they have to be done independently before doing - ;; any assignments. - (begin - (set! speed speed1) - (set! x x1))))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos ; (send w get-pos) - radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will be at its limit, negate the - ;; velocity, otherwise return it unchanged - ;; (define (next-speed) - ;; (if (or - ;; (= (next-x-pos) radius) - ;; (= (next-x-pos) (- wall-pos ; (send w get-pos) - ;; radius))) - ;; (- speed) - ;; speed)) - - (define (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? true] - ;; [saved-mx (- mx x)] - ;; [saved-my (- my y)] - ;; [w w]) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? false] - ;; [saved-mx 127] - ;; [saved-my 98] ; the invariant says that if selected? is - ;; ; false, you can put anything here. - ;; [w w]) - (set! selected? false) - 'error-276)) - - ;; In Racket, an 'if' must have two arms. #lang racket also has a - ;; form called 'when', which only requires one arm. You can use - ;; that in your code if you want. - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - ;; (new Ball% - ;; [x (- mx saved-mx)] - ;; [y (- my saved-my)] - ;; [speed speed] - ;; [selected? true] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the ball ignores key events - (define/public (after-key-event kev) 'error-278) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - - )) - -;; unit test for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SBall -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (begin - (set! pos (- mx saved-mx)) - ;; NEW in push-model: - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/10-8-callbacks.rkt b/Examples/10-8-callbacks.rkt deleted file mode 100644 index b05a4fc..0000000 --- a/Examples/10-8-callbacks.rkt +++ /dev/null @@ -1,655 +0,0 @@ -#lang racket - -;; 10--callbacks: instead of registering 'this', the ball registers a -;; function to be called when it is notified. So we don't need a dedicated -;; update-pos method - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 30) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;; An SBall is an object of any class that implements SBall<%>. - -;; An SBall is like a Ball, but it is stateful (stable), so its -;; interface extends SWidget<%> rather than Widget<%>. - -;; It has one extra method, which updates the ball's copy of the -;; wall's position. - -(define SBall<%> - (interface (SWidget<%>) - - ;; ; Int -> Void - ;; ; EFFECT: updates the ball's cached value of the wall's position - ;; update-wall-pos - - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Instead of waiting to be asked, in this version the wall publishes -;; its position to anyone who puts themselves on the list to be -;; notified. It does so by calling the the recipient's -;; 'update-wall-pos' method. - -;; So SWall<%> has a 'register' method, which allows any SBall to sign up -;; for notifications. - -(define SWall<%> - (interface (SWidget<%>) - - ; (Int -> Void) -> Int - ; GIVEN: A function to be called whenever the wall position changes - ; EFFECT: registers the function to receive position updates from this wall. - ; RETURNS: the x-position of the wall - register - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> World - ;; STRATGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; 10-6: in the push model, the ball is a stateful widget - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))])) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -;; As of 10-6, the Ball is now a stateful widget - -(define SBall% - (class* object% (SWidget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register - ; this - (lambda (n) (set! wall-pos n)))]) - - (super-new) - - ;; ;; Int -> Void - ;; ;; EFFECT: updates the ball's idea of the wall's position to the - ;; ;; given integer. - ;; (define/public (update-wall-pos n) - ;; (set! wall-pos n)) - - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? - this - ;; (new Ball% - ;; [x (next-x-pos)] - ;; [y y] - ;; [speed (next-speed)] - ;; [selected? selected?] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (let ((x1 (next-x-pos)) - (speed1 (next-speed))) - ;; (next-speed) depends on x, and (next-x-pos) depends on - ;; speed, so they have to be done independently before doing - ;; any assignments. - (begin - (set! speed speed1) - (set! x x1))))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos ; (send w get-pos) - radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will be at its limit, negate the - ;; velocity, otherwise return it unchanged - ;; (define (next-speed) - ;; (if (or - ;; (= (next-x-pos) radius) - ;; (= (next-x-pos) (- wall-pos ; (send w get-pos) - ;; radius))) - ;; (- speed) - ;; speed)) - - (define (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? true] - ;; [saved-mx (- mx x)] - ;; [saved-my (- my y)] - ;; [w w]) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? false] - ;; [saved-mx 127] - ;; [saved-my 98] ; the invariant says that if selected? is - ;; ; false, you can put anything here. - ;; [w w]) - (set! selected? false) - 'error-276)) - - ;; In Racket, an 'if' must have two arms. #lang racket also has a - ;; form called 'when', which only requires one arm. You can use - ;; that in your code if you want. - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - ;; (new Ball% - ;; [x (- mx saved-mx)] - ;; [y (- my saved-my)] - ;; [speed speed] - ;; [selected? true] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the ball ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered callbacks - ;; ListOf(Int -> Void) - (field [callbacks empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; (Int -> Void) -> Int - ;; EFFECT: registers the given callback - ;; RETURNS: the current position of the wall - (define/public (register c) - (begin - (set! callbacks (cons c callbacks)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (begin - (set! pos (- mx saved-mx)) - (for-each - (lambda (c) - ; CHANGED in callback model - ; (send b update-wall-pos pos) - (c pos)) - callbacks)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/10-9-interacting-objects.rkt b/Examples/10-9-interacting-objects.rkt deleted file mode 100644 index bfa3d6c..0000000 --- a/Examples/10-9-interacting-objects.rkt +++ /dev/null @@ -1,740 +0,0 @@ -#lang racket - -;; 10-8-interacting-objects. - -;; Based on 10-7-push-model-fixed.rkt - -;; In this version, we'll allow the balls to interact with the wall -;; directly. When a ball is selected, "a" attracts the wall-- moves -;; the wall 50% closer to the ball; "r" repels the wall-- moves the -;; wall 50% farther away. - -;; To do this, we'll add a move-to method to the wall - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) - -;; balls will move slower to make them easier to select. -(define INIT-BALL-SPEED 20) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;; An SBall is an object of any class that implements SBall<%>. - -;; An SBall is like a Ball, but it is stateful (stable), so its -;; interface extends SWidget<%> rather than Widget<%>. - -;; It has one extra method, which updates the ball's copy of the -;; wall's position. - -(define SBall<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Instead of waiting to be asked, in this version the wall publishes -;; its position to anyone who puts themselves on the list to be -;; notified. It does so by calling the the recipient's -;; 'update-wall-pos' method. - -;; So SWall<%> has a 'register' method, which allows any SBall to sign up -;; for notifications. - -;; for 10-9-interacting-objects, we add a move-to method, which allows -;; any object that knows about the wall to move it to a given -;; x-position. - -(define SWall<%> - (interface (SWidget<%>) - - ; SBall -> Int - ; GIVEN: An SBall - ; EFFECT: registers the ball to receive position updates from this wall. - ; RETURNS: the x-position of the wall - register - - ; Int -> Void - ; EFFECT: moves the wall to the given position. Notifies all the - ; registered balls about the change. - move-to - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - - - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; 10-6: in the push model, the ball is a stateful widget - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))])) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -;; As of 10-6, the Ball is now a stateful widget - -(define SBall% - (class* object% (SWidget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the ball's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? - this - ;; (new Ball% - ;; [x (next-x-pos)] - ;; [y y] - ;; [speed (next-speed)] - ;; [selected? selected?] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (let ((x1 (next-x-pos)) - (speed1 (next-speed))) - ;; (next-speed) depends on x, and (next-x-pos) depends on - ;; speed, so they have to be done independently before doing - ;; any assignments. - (begin - (set! speed speed1) - (set! x x1))))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos ; (send w get-pos) - radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will be at its limit, negate the - ;; velocity, otherwise return it unchanged - ;; (define (next-speed) - ;; (if (or - ;; (= (next-x-pos) radius) - ;; (= (next-x-pos) (- wall-pos ; (send w get-pos) - ;; radius))) - ;; (- speed) - ;; speed)) - - (define (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? true] - ;; [saved-mx (- mx x)] - ;; [saved-my (- my y)] - ;; [w w]) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - ;; (new Ball% - ;; [x x][y y][speed speed] - ;; [selected? false] - ;; [saved-mx 127] - ;; [saved-my 98] ; the invariant says that if selected? is - ;; ; false, you can put anything here. - ;; [w w]) - (set! selected? false) - 'error-276)) - - ;; In Racket, an 'if' must have two arms. #lang racket also has a - ;; form called 'when', which only requires one arm. You can use - ;; that in your code if you want. - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - ;; (new Ball% - ;; [x (- mx saved-mx)] - ;; [y (- my saved-my)] - ;; [speed speed] - ;; [selected? true] - ;; [saved-mx saved-mx] - ;; [saved-my saved-my] - ;; [w w]) - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - this)) - - ;; KeyEvent -> Void - (define/public (after-key-event kev) - (if selected? - (cond - [(key=? kev "a") (attract-wall)] - [(key=? kev "r") (repel-wall)]) - this)) - - ;; -> Void - (define (attract-wall) - (send w move-to (- wall-pos (/ (- wall-pos x) 2)))) - - ;; -> Void - (define (repel-wall) - (send w move-to (+ wall-pos (/ (- wall-pos x) 2)))) - - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - - )) - -;; unit test for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SBall -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (begin - (set! pos (- mx saved-mx)) - ;; NEW in push-model: - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - ; move-to : Integer -> Void - ; EFFECT: moves the wall to the specified position, and report the - ; new position to the registered balls - (define/public (move-to n) - (set! pos n) - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - - - ;; probably should combine these for-each's into a single private - ;; function. - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/11-1-flashing-balls.rkt b/Examples/11-1-flashing-balls.rkt deleted file mode 100644 index 04aac5c..0000000 --- a/Examples/11-1-flashing-balls.rkt +++ /dev/null @@ -1,727 +0,0 @@ -#lang racket - -;; 11-1-flashing-balls.rkt : -;; extends 10-7-push-model-fixed by adding a flashing ball ("f") - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 25) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;; An SBall is an object of any class that implements SBall<%>. - -;; An SBall is like a Ball, but it is stateful (stable), so its -;; interface extends SWidget<%> rather than Widget<%>. - -;; It has one extra method, which updates the ball's copy of the -;; wall's position. - -(define SBall<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Instead of waiting to be asked, in this version the wall publishes -;; its position to anyone who puts themselves on the list to be -;; notified. It does so by calling the the recipient's -;; 'update-wall-pos' method. - -;; So SWall<%> has a 'register' method, which allows any SBall to sign up -;; for notifications. - -(define SWall<%> - (interface (SWidget<%>) - - ; SBall -> Int - ; GIVEN: An SBall - ; EFFECT: registers the ball to receive position updates from this wall. - ; RETURNS: the x-position of the wall - register - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> WorldState -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; 10-6: in the push model, the ball is a stateful widget - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))] - [(key=? kev "f") - (send world add-stateful-widget (new FlashingBall% [w wall]))])) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -;; As of 10-6, the Ball is now a stateful widget - -(define SBall% - (class* object% (SWidget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the ball's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? - this - (let ((x1 (next-x-pos)) - (speed1 (next-speed))) - ;; (next-speed) depends on x, and (next-x-pos) depends on - ;; speed, so they have to be done independently before doing - ;; any assignments. - (begin - (set! speed speed1) - (set! x x1))))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos ; (send w get-pos) - radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (set! selected? false) - 'error-276)) - - ;; In Racket, an 'if' must have two arms. #lang racket also has a - ;; form called 'when', which only requires one arm. You can use - ;; that in your code if you want. - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the ball ignores key events - (define/public (after-key-event kev) 'error-278) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - - )) - -;; unit test for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; FlashingBall% is like a SBall%, but it displays differently: it -;; changes color on every fourth tick - -;; Constructor Template for FlashingBall% : -;; (new FlashingBall% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define FlashingBall% - (class* - - ;; inherits from SBall% - SBall% - - ;; still implements SBall<%>, so every object of class - ;; FlashingBall% is an SBall - (SBall<%>) - - ;; number of ticks between color changes - (field [color-change-interval 4]) - - ;; time left til next color change - (field [time-left color-change-interval]) - - ;; the list of possible colors, first element is the current - ;; color. - (field [colors (list "red" "green")]) - - ;; here are fields of the superclass that we need. - ;; note that we have to make radius a field rather than a constant. - (inherit-field radius x y selected?) - - - ;; the value for init-field w is sent to the superclass. - (super-new) - - ;; FlashingBall% behaves just like Ball%, except for add-to-scene. - ;; so we'll find on-tick, on-key, on-mouse methods in Ball% - - ;; Scene -> Scene - ;; RETURNS: a scene like the given one, but with the flashing ball - ;; painted on it. - ;; EFFECT: decrements time-left and changes colors if necessary - (define/override (add-to-scene s) - (begin - ;; is it time to change colors? - (if (zero? time-left) - (change-colors) - (set! time-left (- time-left 1))) - ;; now paint yourself on the scene - (place-image - (circle radius - (if selected? "solid" "outline") - (first colors)) - x y s))) - -;; the place-image could be replaced by (super add-to-scene s) - - ;; -> Void - ;; EFFECT: rotate the list of colors, and reset time-left - (define (change-colors) - (set! colors (append (rest colors) (list (first colors)))) - (set! time-left color-change-interval)) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SBall -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (begin - (set! pos (- mx saved-mx)) - ;; NEW in push-model: - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/11-1-simple.java b/Examples/11-1-simple.java new file mode 100644 index 0000000..352401a --- /dev/null +++ b/Examples/11-1-simple.java @@ -0,0 +1,138 @@ +// simple example of inheritance of methods and fields + +interface I { + + // no purpose; these are just for illustration + int f (); + int g (); + int g1 (); + int h (); +} + +class A implements I { + int i; + int j; + + A () { + System.out.println("calling constructor for A"); + this.i = 15; + this.j = 20; + System.out.println("i = " + i + " j = " + j); + System.out.println(""); + } + + public int f () { + System.out.println("calling method f of class A"); + return (i + j); + } + + public int g () { + System.out.println("calling method g of class A"); + return (i + this.f()); + } + + public int g1 () { + System.out.println("calling method g1 of class A"); + return (i + f()); + } + + public int h () { + System.out.println("calling method h of class A"); + return (i - j); + } +} + +class B extends A implements I { + int k; + + B () { + System.out.println("calling constructor for B"); + k = 200; + System.out.println("i = " + i + " j = " + j + " k = " + k); + System.out.println(""); + } + + public int f (){ + System.out.println("calling method f of class B"); + return 1000; + } + + public int h () { + System.out.println("calling method h of class B"); + return (30 + super.g()); + } + + public int g1() { + System.out.println("calling method g1 of class B"); + return (30 + g()); + } +} + +class C extends B implements I { + + C () { + System.out.println("calling constructor for C"); + j = 100; + } + + public int f () { + System.out.println("calling method f of class C"); + return (j - k); + } + + public int g () { + System.out.println("calling method g of class C"); + return (super.h() + 20); + } + + public int h () { + System.out.println("calling method h of class C"); + return (j + k); + } +} + +class Tests { + + public static void main (String[] args) { + + System.out.println("***Starting tests for class A***"); + + I a1 = new A(); + + show("a1.f()", a1.f()); + show("a1.g()", a1.g()); + show("a1.g1()", a1.g1()); + show("a1.h()", a1.h()); + + System.out.println("\n***Starting tests for class B***"); + + I b1 = new B(); + + show("b1.f()", b1.f()); + show("b1.g()", b1.g()); + show("b1.g1()", b1.g1()); + show("b1.h()", b1.h()); + + System.out.println("\n***Starting tests for class C***"); + + I c1 = new C(); + + show("c1.f()", c1.f()); + show("c1.g()", c1.g()); + show("c1.g1()", c1.g1()); + show("c1.h()", c1.h()); + + + } + + static void show (String str, int n) { + System.out.println(str + "=" + n + "\n"); + } + +} + + + + + + diff --git a/Examples/11-2-simpler.java b/Examples/11-2-simpler.java new file mode 100644 index 0000000..961d4cb --- /dev/null +++ b/Examples/11-2-simpler.java @@ -0,0 +1,140 @@ +// simple example of inheritance of methods and fields + +interface I { + + // no purpose; these are just for illustration + int f (); + int g (); + int g1 (); + int h (); +} + +class A implements I { + int i; + int j; + + A () { + System.out.println("calling constructor for A"); + this.i = 15; + this.j = 20; + System.out.println("i = " + i + " j = " + j); + System.out.println(""); + } + + public int f () { + System.out.println("calling method f of class A"); + return (i + j); + } + + public int g () { + System.out.println("calling method g of class A"); + return (i + this.f()); + } + + public int g1 () { + System.out.println("calling method g1 of class A"); + return (i + f()); + } + + public int h () { + System.out.println("calling method h of class A"); + return (i - j); + } +} + +class B extends A implements I { + int k; + + B () { + System.out.println("calling constructor for B"); + k = 200; + System.out.println("i = " + i + " j = " + j + " k = " + k); + System.out.println(""); + } + + public int f () { + System.out.println("calling method f()=this.h() of class B"); + return (this.h()); // which h gets called? + } + + public int g () { + System.out.println("calling method g()=super.h() of class B"); + return (super.h()); // which h gets called? + } + + public int g1 () { + System.out.println("calling method g1=h() of class B"); + // which h gets called? + return (h()); + } + + public int h () { + System.out.println("calling method h of class B"); + return (30); + } + + + +} + +class C extends B implements I { + + C () { + System.out.println("calling constructor for C"); + j = 100; + System.out.println("i = " + i + " j = " + j + " k = " + k); + System.out.println(""); + + } + + public int h () { + System.out.println("calling method h of class C"); + return (j + k); + } +} + +class Tests { + + public static void main (String[] args) { + + System.out.println("***Starting tests for class A***\n"); + + I a1 = new A(); + + show("a1.f()", a1.f()); + show("a1.g()", a1.g()); + show("a1.g1()", a1.g1()); + show("a1.h()", a1.h()); + + System.out.println("\n***Starting tests for class B***\n"); + + I b1 = new B(); + + show("b1.f()", b1.f()); + show("b1.g()", b1.g()); + show("b1.g1()", b1.g1()); + show("b1.h()", b1.h()); + + System.out.println("\n***Starting tests for class C***\n"); + + I c1 = new C(); + + show("c1.f()", c1.f()); + show("c1.g()", c1.g()); + show("c1.g1()", c1.g1()); + show("c1.h()", c1.h()); + + + } + + static void show (String str, int n) { + System.out.println(str + "=" + n + "\n"); + } + +} + + + + + + diff --git a/Examples/11-2-squares.rkt b/Examples/11-2-squares.rkt deleted file mode 100644 index af2c9f6..0000000 --- a/Examples/11-2-squares.rkt +++ /dev/null @@ -1,865 +0,0 @@ -#lang racket - -;; 11-2-squares.rkt -;; adds squares ("s") - -;; 11-1-flashing-balls.rkt : -;; extends 10-7-push-model-fixed by adding a flashing ball ("f") - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 25) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;; An SBall is an object of any class that implements SBall<%>. - -;; An SBall is like a Ball, but it is stateful (stable), so its -;; interface extends SWidget<%> rather than Widget<%>. - -;; It has one extra method, which updates the ball's copy of the -;; wall's position. - -(define SBall<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Instead of waiting to be asked, in this version the wall publishes -;; its position to anyone who puts themselves on the list to be -;; notified. It does so by calling the the recipient's -;; 'update-wall-pos' method. - -;; So SWall<%> has a 'register' method, which allows any SBall to sign up -;; for notifications. - -(define SWall<%> - (interface (SWidget<%>) - - ; SBall -> Int - ; GIVEN: An SBall - ; EFFECT: registers the ball to receive position updates from this wall. - ; RETURNS: the x-position of the wall - register - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> WorldState -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; 10-6: in the push model, the ball is a stateful widget - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))] - [(key=? kev "f") - (send world add-stateful-widget (new FlashingBall% [w wall]))] - [(key=? kev "s") - (send world add-stateful-widget (new Square% [w wall]))] -)) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -;; As of 10-6, the Ball is now a stateful widget - -(define SBall% - (class* object% (SWidget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the ball's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? - this - (let ((x1 (next-x-pos)) - (speed1 (next-speed))) - ;; (next-speed) depends on x, and (next-x-pos) depends on - ;; speed, so they have to be done independently before doing - ;; any assignments. - (begin - (set! speed speed1) - (set! x x1))))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos ; (send w get-pos) - radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (set! selected? false) - 'error-276)) - - ;; In Racket, an 'if' must have two arms. #lang racket also has a - ;; form called 'when', which only requires one arm. You can use - ;; that in your code if you want. - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the ball ignores key events - (define/public (after-key-event kev) 'error-278) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - - )) - -;; unit test for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A FlashingBall% is like a SBall%, but it displays differently: it -;; changes color on every fourth tick - -;; Constructor Template for FlashingBall% : -;; Constructor template for SBall%: -;; (new FlashingBall% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define FlashingBall% - (class* - SBall% ; inherits from SBall% - (SBall<%>) ; still implements SBall<%>, so every object of class FlashingBall% is an SBall - - (field [color-change-interval 4]) ; how much time between color changes? - (field [time-left color-change-interval]) ; how much time left - ; til next color change - - (field [colors (list "red" "green")]) ; the list of possible - ; colors, first elt is current color - - ;; here are fields of the superclass that we need. - ;; note that we have to make radius a field rather than a constant. - (inherit-field radius x y selected?) - - - ;; the value for init-field w is sent to the superclass. - (super-new) - - ;; FlashingBall% behaves just like Ball%, except for add-to-scene. - ;; so we'll find on-tick, on-key, on-mouse methods in Ball% - - ;; Scene -> Scene - ;; RETURNS: a scene like the given one, but with the flashing ball - ;; painted on it. - ;; EFFECT: decrements time-left and changes colors if necessary - (define/override (add-to-scene s) - (begin - ;; is it time to change colors? - (if (zero? time-left) - (change-colors) - (set! time-left (- time-left 1))) - ;; now paint yourself on the scene - (place-image - (circle radius - (if selected? "solid" "outline") - (first colors)) - x y s))) - -;; the place-image could be replaced by (super add-to-scene s) - - ;; -> Void - ;; EFFECT: rotate the list of colors, and reset time-left - (define (change-colors) - (set! colors (append (rest colors) (list (first colors)))) - (set! time-left color-change-interval)) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; Square is like Ball, but it has different geometry. - -(define Square% - (class* object% (SBall<%>) - - (init-field w) ;; the Wall that the square should bounce off of - - ;; initial values of x, y (center of square) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; square's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [size 40]) - (field [half-size (/ size 2)]) - - ;; register this square with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the square's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - ;; after-tick : -> Void - ;; state of this square after a tick. A selected square doesn't move. - - (define/public (after-tick) - (if selected? - this - (let ((x1 (next-x-pos)) - (speed1 (next-speed))) - ;; (next-speed) depends on x, and (next-x-pos) depends on - ;; speed, so they have to be done independently before doing - ;; any assignments. - (begin - (set! speed speed1) - (set! x x1))))) - - ;; -> Integer - ;; position of the square at the next tick - ;; STRATEGY: use the square's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - half-size - (+ x speed) - (- wall-pos half-size))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the square at the next tick - ;; STRATEGY: if the square will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define (next-speed) - (if - (< half-size (next-x-pos) (- wall-pos half-size)) - speed - (- speed))) - - (define/public (add-to-scene s) - (place-image - (square size - (if selected? "solid" "outline") - "green") - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (and - (<= (- x half-size) other-x (+ x half-size)) - (<= (- y half-size) other-y (+ y half-size)))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (set! selected? false) - this)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the square is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - this)) - - ;; the square ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SBall -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (begin - (set! pos (- mx saved-mx)) - ;; NEW in push-model: - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/11-3-complex.java b/Examples/11-3-complex.java new file mode 100644 index 0000000..0023ae3 --- /dev/null +++ b/Examples/11-3-complex.java @@ -0,0 +1,129 @@ +// more complicated examples of inheritance and fields + +interface I { + int f (); + int g (); + int h (); +} + +class A implements I { + int i = 15; + int j = 20; + + A () { + System.out.println("calling constructor for A"); + show("i", i); show("j", j); + } + + // EFFECT: increments i + // RETURNS: the new value of i + j + + public int f () { + System.out.println("calling method f of class A"); + i = i + 1; + return (i + j); + } + + // RETURNS: mystery!! + + public int g () { + System.out.println("calling method g of class A"); + return (this.f() + 1); + } + + public int h () { + System.out.println("calling method g of class A"); + j = j + 10; + return (i - j); + } + + public void show (String str, int n) { + System.out.println(str + "=" + n); + } + + +} + +class B extends A implements I { + int k = 200; + + B () { + System.out.println("calling constructor for B"); + j = 100; + int n = this.h(); + show("i", i); show("j", j); show("k", k); + } + + public int g () { + System.out.println("calling method g of class B"); + return (i + j - k); + } + + public int h () { + System.out.println("calling method h of class B"); + j = j + 100; + return (super.g() + 30); + } + +} + + +class C extends B implements I { + + C () { + System.out.println("calling constructor for C"); + show("i", i); show("j", j); show("k", k); + } + + public int f () { + System.out.println("calling method f of class C"); + return (j - k); + } + + public int g () { + System.out.println("calling method g of class C"); + return (super.h() + 20); + } + + public int h () { + System.out.println("calling method h of class C"); + k = k + 20; + return (j + k); + } +} +class Tests { + + public static void main (String[] args) { + + System.out.println("***Starting tests for class A***"); + + I a1 = new A(); + + show("a1.f()", a1.f()); + show("a1.g()", a1.g()); + show("a1.h()", a1.h()); + + System.out.println("\n***Starting tests for class B***"); + + I b1 = new B(); + + show("b1.f()", b1.f()); + show("b1.g()", b1.g()); + show("b1.h()", b1.h()); + + System.out.println("\n***Starting tests for class C***"); + + I c1 = new C(); + + show("c1.f()", c1.f()); + show("c1.g()", c1.g()); + show("c1.h()", c1.h()); + + + } + + public static void show (String str, int n) { + System.out.println(str + "=" + n + "\n"); + } + +} diff --git a/Examples/11-3-unify-try1.rkt b/Examples/11-3-unify-try1.rkt deleted file mode 100644 index 4bde852..0000000 --- a/Examples/11-3-unify-try1.rkt +++ /dev/null @@ -1,1042 +0,0 @@ -#lang racket - -;; 11-3-unify-try1.rkt -;; Factor common parts of implementation of SBall% and Square% -;; into a superclass DraggableWidget% - -;; We'll do this by simply copying SBall% to DraggableWidget% and -;; commenting out the parts that differ between SBall% and Square%. - -;; 11-2-squares.rkt -;; adds squares ("s") - -;; 11-1-flashing-balls.rkt : -;; extends 10-7-push-model-fixed by adding a flashing ball ("f") - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 25) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;; An SBall is an object of any class that implements SBall<%>. - -;; An SBall is like a Ball, but it is stateful (stable), so its -;; interface extends SWidget<%> rather than Widget<%>. - -;; It has one extra method, which updates the ball's copy of the -;; wall's position. - -(define SBall<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; The wall will be stable (stateful), so its interface -;; extends SWidget<%> instead of Widget<%>. - -;; An SWall is an object of any class that implements SWall<%>. -;; There will be only one such class. - -;; SWall<%> extends SWidget<%> instead of Widget<%>. - -;; Instead of waiting to be asked, in this version the wall publishes -;; its position to anyone who puts themselves on the list to be -;; notified. It does so by calling the the recipient's -;; 'update-wall-pos' method. - -;; So SWall<%> has a 'register' method, which allows any SBall to sign up -;; for notifications. - -(define SWall<%> - (interface (SWidget<%>) - - ; SBall -> Int - ; GIVEN: An SBall - ; EFFECT: registers the ball to receive position updates from this wall. - ; RETURNS: the x-position of the wall - register - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> WorldState -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new BallFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The BallFactory% class - -;; accepts "b" key events and adds them to the world. -;; gets the world as an init-field - -;; 10-6: in the push model, the ball is a stateful widget - -(define BallFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - ; KeyEvent -> Void - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))] - [(key=? kev "f") - (send world add-stateful-widget (new FlashingBall% [w wall]))] - [(key=? kev "s") - (send world add-stateful-widget (new Square% [w wall]))] - )) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The DraggableWidget% class - -;; Constructor Template for DraggableWidget%: -;;(new DraggableWidget% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define DraggableWidget% - (class* object% - - ;; we're not renaming the interface, at least for now - (SBall<%>) - - ;; the Wall that the ball should bounce off of - (init-field w) - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; this is specific to Ball% - ; (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the ball's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? - this - (let ((x1 (next-x-pos)) - (speed1 (next-speed))) - (begin - (set! speed speed1) - (set! x x1))))) - - ;; circle-specific - ;; -> Integer - ;; position of the object at the next tick - ;; (define (next-x-pos) - ;; (limit-value - ;; radius - ;; (+ x speed) - ;; (- wall-pos radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - ;; (define (next-speed) - ;; (if - ;; (< radius (next-x-pos) (- wall-pos radius)) - ;; speed - ;; (- speed))) - - ;; also circle specific - ;; (define/public (add-to-scene s) - ;; (place-image - ;; (circle radius - ;; "outline" - ;; "red") - ;; x y s)) - - ;; but we need to declare it, so that we'll satisfy the interface: - (abstract add-to-scene) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - -;;; **************************************************************** - - ;;; OH NO! Look what happens when we load this file: - - ;;; 11-3-unify-try1.rkt:451:11: in-this?: unbound identifier in module in: in-this? - -;;; **************************************************************** - - ;; also circle-specific - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - ;; (define (in-this? other-x other-y) - ;; (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - ;; (sqr radius))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (set! selected? false) - 'error-276)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the widget ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The Ball% class - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -;; As of 10-6, the Ball is now a stateful widget - -(define SBall% - (class* - - ;; inherit method implementations from DraggableWidget% - DraggableWidget% - - (SBall<%>) - - ;; inherit all these fields from the superclass - (inherit-field w) ;; the Wall that the ball should bounce off of - ;; initial values of x, y (center of ball) and speed: - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (inherit-field [saved-mx 0] [saved-my 0]) - - ;; this field is local to Ball% - (field [radius 20]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - ;;(field [wall-pos (send w register this)]) - ;; the superclass will do this. - (inherit-field wall-pos) - - (super-new) - - ;; all this is common: - - ;; ;; Int -> Void - ;; ;; EFFECT: updates the ball's idea of the wall's position to the - ;; ;; given integer. - ;; (define/public (update-wall-pos n) - ;; (set! wall-pos n)) - - - ;; ;; after-tick : -> Void - ;; ;; state of this ball after a tick. A selected ball doesn't move. - ;; (define/public (after-tick) - ;; (if selected? - ;; this - ;; (let ((x1 (next-x-pos)) - ;; (speed1 (next-speed))) - ;; (begin - ;; (set! speed speed1) - ;; (set! x x1))))) - - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos ; (send w get-pos) - radius))) - - ;; we'll leave this one here for the time being: - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; ball-specific: - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - ;; this overrides the 'abstract' in the superclass. - (define/override (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ;; ; after-button-down : Integer Integer -> Void - ;; ; GIVEN: the location of a button-down event - ;; ; STRATEGY: Cases on whether the event is in this - ;; (define/public (after-button-down mx my) - ;; (if (in-this? mx my) - ;; (begin - ;; (set! selected? true) - ;; (set! saved-mx (- mx x)) - ;; (set! saved-my (- my y))) - ;; this)) - - ;; ball-specific: - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ;; ; after-button-up : Integer Integer -> Void - ;; ; GIVEN: the location of a button-up event - ;; ; STRATEGY: Cases on whether the event is in this - ;; ; If this is selected, then unselect it. - ;; (define/public (after-button-up mx my) - ;; (if (in-this? mx my) - ;; (set! selected? false) - ;; this)) - - ;; ; after-drag : Integer Integer -> Void - ;; ; GIVEN: the location of a drag event - ;; ; STRATEGY: Cases on whether the ball is selected. - ;; ; If it is selected, move it so that the vector from the center to - ;; ; the drag event is equal to (mx, my) - ;; (define/public (after-drag mx my) - ;; (if selected? - ;; (begin - ;; (set! x (- mx saved-mx)) - ;; (set! y (- my saved-my))) - ;; this)) - - ;; ;; the ball ignores key events - ;; (define/public (after-key-event kev) this) - - ;; (define/public (for-test:x) x) - ;; (define/public (for-test:speed) speed) - ;; (define/public (for-test:wall-pos) wall-pos) - ;; (define/public (for-test:next-speed) (next-speed)) - ;; (define/public (for-test:next-x) (next-x-pos)) - - - )) - -;; unit test for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A FlashingBall% is like a SBall%, but it displays differently: it -;; changes color on every fourth tick - -;; Constructor Template for FlashingBall% : -;; Constructor template for SBall%: -;; (new FlashingBall% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define FlashingBall% - (class* - SBall% ; inherits from SBall% - (SBall<%>) ; still implements SBall<%>, so every object of class FlashingBall% is an SBall - - (field [color-change-interval 4]) ; how much time between color changes? - (field [time-left color-change-interval]) ; how much time left - ; til next color change - - (field [colors (list "red" "green")]) ; the list of possible - ; colors, first elt is current color - - ;; here are fields of the superclass that we need. - ;; note that we have to make radius a field rather than a constant. - (inherit-field radius x y selected?) - - - ;; the value for init-field w is sent to the superclass. - (super-new) - - ;; FlashingBall% behaves just like Ball%, except for add-to-scene. - ;; so we'll find on-tick, on-key, on-mouse methods in Ball% - - ;; Scene -> Scene - ;; RETURNS: a scene like the given one, but with the flashing ball - ;; painted on it. - ;; EFFECT: decrements time-left and changes colors if necessary - (define/override (add-to-scene s) - (begin - ;; is it time to change colors? - (if (zero? time-left) - (change-colors) - (set! time-left (- time-left 1))) - ;; now paint yourself on the scene - (place-image - (circle radius - (if selected? "solid" "outline") - (first colors)) - x y s))) - -;; the place-image could be replaced by (super add-to-scene s) - - ;; -> Void - ;; EFFECT: rotate the list of colors, and reset time-left - (define (change-colors) - (set! colors (append (rest colors) (list (first colors)))) - (set! time-left color-change-interval)) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; now we'll do the same thing for Square%: - -;; Square is like Ball, but it has different geometry. - -(define Square% - (class* object% (SBall<%>) - - (inherit-field w) ;; the Wall that the square should bounce off of - - ;; initial values of x, y (center of square) - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; square's center. Else any value. - (inherit-field saved-mx saved-my) - - (field [size 40]) - (field [half-size (/ size 2)]) - - ;; register this square with the wall, and use the result as the - ;; initial value of wall-pos - ; (field [wall-pos (send w register this)]) - (inherit-field wall-pos) - - (super-new) - - ;; ;; Int -> Void - ;; ;; EFFECT: updates the square's idea of the wall's position to the - ;; ;; given integer. - ;; (define/public (update-wall-pos n) - ;; (set! wall-pos n)) - - ;; ;; after-tick : -> Void - ;; ;; state of this square after a tick. A selected square doesn't move. - - ;; (define/public (after-tick) - ;; (if selected? - ;; this - ;; (let ((x1 (next-x-pos)) - ;; (speed1 (next-speed))) - ;; ;; (next-speed) depends on x, and (next-x-pos) depends on - ;; ;; speed, so they have to be done independently before doing - ;; ;; any assignments. - ;; (begin - ;; (set! speed speed1) - ;; (set! x x1))))) - - ;; Square-specific: - - ;; -> Integer - ;; position of the square at the next tick - ;; STRATEGY: use the square's cached copy of the wall position to - ;; set the upper limit of motion - (define (next-x-pos) - (limit-value - half-size - (+ x speed) - (- wall-pos half-size))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; Square-specific - - ;; -> Integer - ;; RETURNS: the velocity of the square at the next tick - ;; STRATEGY: if the square will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define (next-speed) - (if - (< half-size (next-x-pos) (- wall-pos half-size)) - speed - (- speed))) - - (define/public (add-to-scene s) - (place-image - (square size - (if selected? "solid" "outline") - "green") - x y s)) - - ;; ; after-button-down : Integer Integer -> Void - ;; ; GIVEN: the location of a button-down event - ;; ; STRATEGY: Cases on whether the event is in this - ;; (define/public (after-button-down mx my) - ;; (if (in-this? mx my) - ;; (begin - ;; (set! selected? true) - ;; (set! saved-mx (- mx x)) - ;; (set! saved-my (- my y))) - ;; this)) - - ;; square-specific: - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define (in-this? other-x other-y) - (and - (<= (- x half-size) other-x (+ x half-size)) - (<= (- y half-size) other-y (+ y half-size)))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (set! selected? false) - this)) - - ;; ; after-drag : Integer Integer -> Void - ;; ; GIVEN: the location of a drag event - ;; ; STRATEGY: Cases on whether the square is selected. - ;; ; If it is selected, move it so that the vector from the center to - ;; ; the drag event is equal to (mx, my) - ;; (define/public (after-drag mx my) - ;; (if selected? - ;; (begin - ;; (set! x (- mx saved-mx)) - ;; (set! y (- my saved-my))) - ;; this)) - - ;; ;; the square ignores key events - ;; (define/public (after-key-event kev) this) - - ;; (define/public (for-test:x) x) - ;; (define/public (for-test:speed) speed) - ;; (define/public (for-test:wall-pos) wall-pos) - ;; (define/public (for-test:next-speed) (next-speed)) - ;; (define/public (for-test:next-x) (next-x-pos)) - - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SBall -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - ;; (new Wall% - ;; [pos pos] - ;; [selected? true] - ;; [saved-mx (- mx pos)]) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - ;; (new Wall% - ;; [pos pos] - ;; [selected? false] - ;; [saved-mx saved-mx]) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered listeners - (define/public (after-drag mx my) - (if selected? - ;; (new Wall% - ;; [pos (- mx saved-mx)] - ;; [selected? true] - ;; [saved-mx saved-mx]) - (begin - (set! pos (- mx saved-mx)) - ;; NEW in push-model: - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/11-4-turn-differences-into-methods.rkt b/Examples/11-4-turn-differences-into-methods.rkt deleted file mode 100644 index 8ca441b..0000000 --- a/Examples/11-4-turn-differences-into-methods.rkt +++ /dev/null @@ -1,854 +0,0 @@ -#lang racket - -;; 11-4-turn-differences-into-methods.rkt -;; local functions in the subclasses weren't accessible from the -;; superclass. -;; So turn them into methods, and call them with 'this' -;; We'll clean up a bit as we go, so we can see what we're doing. - -;; 11-3-unify-try1.rkt -;; Factor common parts of implementation of Ball% and Square% -;; into a superclass DraggableWidget% - -;; We'll do this by simply copying SBall% to DraggableWidget% and -;; commenting out the parts that differ between SBall% and Square%. - -;; 11-2-squares.rkt -;; adds squares ("s") - -;; 11-1-flashing-balls.rkt : -;; extends 10-7-push-model-fixed by adding a flashing ball ("f") - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 25) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; while we're at it, we'll rename the interfaces to reflect their -;; generic nature. - -;; Additional method for SBall% and other classes that receive messages -;; from the wall: - -(define SWidgetListener<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; Additional method for classes that send messages to -;; SWidgetListeners. In our example, SWall% is the only such class. - -(define SWidgetPublisher<%> - (interface (SWidget<%>) - - ; SWidgetListener -> Int - ; GIVEN: An SWidgetListener - ; EFFECT: registers the listener to receive position updates from this wall. - ; RETURNS: the current x-position of the wall - register - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> WorldState -;; RETURNS: a world with a wall, a ball, and a factory - -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty - (list the-ball the-wall))) - (define the-factory - (new WidgetFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; The WidgetFactory% class - -;; accepts key events and adds SWidgetListeners to the world. - -;; gets the world as an init-field - -(define WidgetFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - ; KeyEvent -> Void - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))] - [(key=? kev "f") - (send world add-stateful-widget (new FlashingBall% [w wall]))] - [(key=? kev "s") - (send world add-stateful-widget (new Square% [w wall]))] - )) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Constructor Template for DraggableWidget%: -;;(new DraggableWidget% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define DraggableWidget% - (class* object% - - ;; the methods implemented in the superclass - ; (DraggableWidget<%>) - (SWidgetListener<%>) - - ;; the methods to be supplied by each subclass - (abstract add-to-scene - next-x-pos - next-speed - in-this?) - - - ;; the Wall that the ball should bounce off of - (init-field w) - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; object's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the widget's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected widget doesn't move. - (define/public (after-tick) - (if selected? - this - (let ((x1 (send this next-x-pos)) - (speed1 (send this next-speed))) - (begin - (set! speed speed1) - (set! x x1))))) - - - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if - ;; (in-this? mx my) - (send this in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if - ;; (in-this? mx my) - (send this in-this? mx my) - (set! selected? false) - 'error-276)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the widget ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - )) - - -;; Hooks left over: these methods must be filled in from subclass. - -(define DraggableWidgetHooks<%> - (interface () - - ;; Int Int -> Boolean - ;; is the given location in this widget? - in-this? - - ;; -> Int - ;; RETURNS: the next x position or speed of this widget - next-x-pos - next-speed - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define SBall% - (class* - - ;; inherit method implementations from DraggableWidget% - DraggableWidget% - - ;; must implement the interface(s) of DraggableWidget% + the open - ;; hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - ;; inherit all these fields from the superclass: - - ;; the Wall that the ball should bounce off of - (inherit-field w) - - ;; initial values of x, y (center of ball) and speed: - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - ;; position of the wall, updated by update-wall-pos - (inherit-field wall-pos) - - ; don't need to inherit these: all dragging is handled in the superclass - ;(inherit-field [saved-mx 0] [saved-my 0]) - - ;; this field is local to Ball% - (field [radius 20]) - - (super-new) - - ;; make this a method instead of a function: - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; make this a method instead of a function: - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - - - (define/override (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - )) - -;; unit tests for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A FlashingBall% is like a SBall%, but it displays differently: it -;; changes color on every fourth tick - -;; Constructor Template for FlashingBall% : -;; Constructor template for SBall%: -;; (new FlashingBall% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define FlashingBall% - (class* SBall% (SWidgetListener<%>) ; - - ;; here are fields of the superclass that we need. - ;; we should copy the interpretations here so we'll know what they mean. - (inherit-field radius x y selected?) - - ; how much time between color changes? - (field [color-change-interval 4]) - ; time left til next color change - (field [time-left color-change-interval]) - ; the list of possible colors, first elt is current color - (field [colors (list "red" "green")]) - - ;; the value for init-field w is sent to the superclass. - (super-new) - - ;; FlashingBall% behaves just like Ball%, except for add-to-scene. - ;; so we'll find on-tick, on-key, on-mouse methods in Ball% - - ;; Scene -> Scene - ;; RETURNS: a scene like the given one, but with the flashing ball - ;; painted on it. - ;; EFFECT: decrements time-left and changes colors if necessary - (define/override (add-to-scene s) - (begin - ;; is it time to change colors? - (if (zero? time-left) - (change-colors) - (set! time-left (- time-left 1))) - ;; now paint yourself on the scene - (place-image - (circle radius - (if selected? "solid" "outline") - (first colors)) - x y s))) - -;; the place-image could be replaced by (super add-to-scene s) - - ;; -> Void - ;; EFFECT: rotate the list of colors, and reset time-left - (define (change-colors) - (set! colors (append (rest colors) (list (first colors)))) - (set! time-left color-change-interval)) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; now we'll do the same thing for Square%: - -;; Square is like Ball, but it has different geometry. - -(define Square% - (class* DraggableWidget% - - ;; must implement SWidgetListener + the open hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - (inherit-field w) ;; the Wall that the square should bounce off of - - ;; initial values of x, y (center of square) - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - (inherit-field wall-pos) - - ;; don't need saved-mx saved-my - ;; (inherit-field saved-mx saved-my) - - (field [size 40]) - (field [half-size (/ size 2)]) - - (super-new) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; position of the square at the next tick - ;; STRATEGY: use the square's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - half-size - (+ x speed) - (- wall-pos half-size))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; RETURNS: the velocity of the square at the next tick - ;; STRATEGY: if the square will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< half-size (next-x-pos) (- wall-pos half-size)) - speed - (- speed))) - - (define/override (add-to-scene s) - (place-image - (square size - (if selected? "solid" "outline") - "green") - x y s)) - - ;; square-specific: - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (and - (<= (- x half-size) other-x (+ x half-size)) - (<= (- y half-size) other-y (+ y half-size)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWidgetPublisher<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SWidgetListener -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered listeners - (define/public (after-drag mx my) - (if selected? - (begin - (set! pos (- mx saved-mx)) - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/11-5-generalize-methods-in-superclass.rkt b/Examples/11-5-generalize-methods-in-superclass.rkt deleted file mode 100644 index 3ab0294..0000000 --- a/Examples/11-5-generalize-methods-in-superclass.rkt +++ /dev/null @@ -1,865 +0,0 @@ -#lang racket - -;; 11-5-generalize-methods-in-superclass.rkt -;; If there are methods that are similar but not identical, generalize -;; them and put the generalization in the superclass. They can pick -;; up the differences using a hook method. - -;; Here we'll do that with add-to-scene. - -;; 11-4-turn-differences-into-methods.rkt -;; local functions in the subclasses weren't accessible from the -;; superclass. -;; So turn them into methods, and call them with 'this' -;; We'll clean up a bit as we go, so we can see what we're doing. - - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 25) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: a location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; while we're at it, we'll rename the interfaces to reflect their -;; generic nature. - -;; Additional method for SBall% and other classes that receive messages -;; from the wall: - -(define SWidgetListener<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; Additional method for classes that send messages to -;; SWidgetListeners. In our example, SWall% is the only such class. - -(define SWidgetPublisher<%> - (interface (SWidget<%>) - - ; SWidgetListener -> Int - ; GIVEN: An SWidgetListener - ; EFFECT: registers the listener to receive position updates from this wall. - ; RETURNS: the current x-position of the wall - register - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> WorldState -;; RETURNS: a world with a wall, a ball, and a factory -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty ; (list the-ball) -- the ball is now stateful - (list the-wall))) - (define the-factory - (new WidgetFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear.. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The WidgetFactory% class - -;; accepts key events and adds SWidgetListeners to the world. - -;; gets the world as an init-field - -(define WidgetFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - ; KeyEvent -> Void - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))] - [(key=? kev "f") - (send world add-stateful-widget (new FlashingBall% [w wall]))] - [(key=? kev "s") - (send world add-stateful-widget (new Square% [w wall]))] - )) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Constructor template for DraggableWidget%: -;; (new DraggableWidget% [w Wall]) - -;; the Ball is now a stateful widget - -(define DraggableWidget% - (class* object% - - ;; the methods implemented in the superclass - ; (DraggableWidget<%>) - (SWidgetListener<%>) - - ;; the methods to be supplied by each subclass - (abstract ; add-to-scene - next-x-pos - next-speed - in-this?) - - - ;; the Wall that the ball should bounce off of - (init-field w) - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; object's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the widget's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected widget doesn't move. - (define/public (after-tick) - (if selected? - this - (let ((x1 (send this next-x-pos)) - (speed1 (send this next-speed))) - (begin - (set! speed speed1) - (set! x x1))))) - - ;; instead of having add-to-scene an abstract method, we keep it - ;; in the superclass, and make the differences abstract: - - ; (abstract add-to-scene) - (define/public (add-to-scene s) - (place-image - (send this get-image) - x y s)) - - (abstract get-image) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if - ;; (in-this? mx my) - (send this in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ;; to be supplied by the subclass - ;; (abstract in-this?) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if - ;; (in-this? mx my) - (send this in-this? mx my) - (set! selected? false) - 'error-276)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the widget ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - )) - - -;; Hooks left over: these methods must be filled in from subclass. -(define DraggableWidgetHooks<%> - (interface () - - ;; Int Int -> Boolean - ;; is the given location in this widget? - in-this? - - ;; -> Int - ;; RETURNS: the next x position or speed of this widget - next-x-pos - next-speed - - ;; -> Image - ;; RETURNS: the image of this widget for display - get-image - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define SBall% - (class* - - ;; inherit method implementations from DraggableWidget% - DraggableWidget% - - ;; must implement the interface(s) of DraggableWidget% + the open - ;; hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - ;; inherit all these fields from the superclass: - - ;; the Wall that the ball should bounce off of - (inherit-field w) - - ;; initial values of x, y (center of ball) and speed: - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - ;; position of the wall, updated by update-wall-pos - (inherit-field wall-pos) - - ;; this field is local to Ball% - (field [radius 20]) - - (super-new) - - ;; make this a method instead of a function: - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; make this a method instead of a function: - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - ;; (define/override (add-to-scene s) - ;; (place-image - ;; (circle radius - ;; "outline" - ;; "red") - ;; x y s)) - - (define/override (get-image) - (circle radius - "outline" - "red")) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - )) - -;; unit tests for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A FlashingBall% is like a SBall%, but it displays differently: it -;; changes color on every fourth tick - -;; Constructor Template for FlashingBall% : -;; Constructor template for SBall%: -;; (new FlashingBall% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define FlashingBall% - (class* SBall% (SWidgetListener<%>) ; - - ;; here are fields of the superclass that we need. - ;; we should copy the interpretations here so we'll know what they mean. - (inherit-field radius x y selected?) - - ; how much time between color changes? - (field [color-change-interval 4]) - ; time left til next color change - (field [time-left color-change-interval]) - ; the list of possible colors, first elt is current color - (field [colors (list "red" "green")]) - - ;; the value for init-field w is sent to the superclass. - (super-new) - - ;; FlashingBall% behaves just like Ball%, except for add-to-scene. - ;; so we'll find on-tick, on-key, on-mouse methods in Ball% - - ;; Scene -> Scene - ;; RETURNS: a scene like the given one, but with the flashing ball - ;; painted on it. - ;; EFFECT: decrements time-left and changes colors if necessary - (define/override (add-to-scene s) - (begin - ;; is it time to change colors? - (if (zero? time-left) - (change-colors) - (set! time-left (- time-left 1))) - ;; call the super - (super add-to-scene s))) - - (define/override (get-image) - (circle radius - (if selected? "solid" "outline") - (first colors))) - - ;; -> Void - ;; EFFECT: rotate the list of colors, and reset time-left - (define (change-colors) - (set! colors (append (rest colors) (list (first colors)))) - (set! time-left color-change-interval)) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; now we'll do the same thing for Square%: - -;; Square is like Ball, but it has different geometry. - -(define Square% - (class* DraggableWidget% - - ;; must implement SWidgetListener + the open hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - (inherit-field w) ;; the Wall that the square should bounce off of - - ;; initial values of x, y (center of square) - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - (inherit-field wall-pos) - - ;; don't need saved-mx saved-my - ;; (inherit-field saved-mx saved-my) - - (field [size 40]) - (field [half-size (/ size 2)]) - - (super-new) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; position of the square at the next tick - ;; STRATEGY: use the square's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - half-size - (+ x speed) - (- wall-pos half-size))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; RETURNS: the velocity of the square at the next tick - ;; STRATEGY: if the square will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< half-size (next-x-pos) (- wall-pos half-size)) - speed - (- speed))) - - ;; (define/override (add-to-scene s) - ;; (place-image - ;; (square size - ;; (if selected? "solid" "outline") - ;; "green") - ;; x y s)) - - (define/override (get-image) - (square size - (if selected? "solid" "outline") - "green")) - - ;; square-specific: - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (and - (<= (- x half-size) other-x (+ x half-size)) - (<= (- y half-size) other-y (+ y half-size)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWidgetPublisher<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - (init-field [saved-mx 0]) - - ;; the list of registered balls - ;; ListOfBall - (field [balls empty]) - - (super-new) - - ;; the extra behavior for Wall<%> - ;; (define/public (get-pos) pos) - - ;; SWidgetListener -> Int - ;; EFFECT: registers the given ball - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! balls (cons b balls)) - pos)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - ;; don't need to worry about returning this - this)) ;; but an if needs an else clause :-( - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - (set! selected? false)) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered listeners - (define/public (after-drag mx my) - (if selected? - (begin - (set! pos (- mx saved-mx)) - (for-each - (lambda (b) (send b update-wall-pos pos)) - balls)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/11-6-after-review.rkt b/Examples/11-6-after-review.rkt deleted file mode 100644 index f119c01..0000000 --- a/Examples/11-6-after-review.rkt +++ /dev/null @@ -1,838 +0,0 @@ -#lang racket - -;; 11-6-after-review.rkt -;; Clean up and review. - -;; 11-5-generalize-methods-in-superclass.rkt -;; If there are methods that are similar but not identical, generalize -;; them and put the generalization in the superclass. They can pick -;; up the differences using a hook method. - -;; Here we'll do that with add-to-scene. - -;; 11-4-turn-differences-into-methods.rkt -;; local functions in the subclasses weren't accessible from the -;; superclass. -;; So turn them into methods, and call them with 'this' -;; We'll clean up a bit as we go, so we can see what we're doing. - - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-WIDGET-X (/ CANVAS-HEIGHT 2)) -(define INIT-WIDGET-Y (/ CANVAS-WIDTH 3)) -(define INIT-WIDGET-SPEED 25) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: an (x,y) location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: an (x,y) location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; while we're at it, we'll rename the interfaces to reflect their -;; generic nature. - -;; Additional method for SBall% and other classes that receive messages -;; from the wall: - -(define SWidgetListener<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; Additional method for classes that send messages to -;; SWidgetListeners. In our example, SWall% is the only such class. - -(define SWidgetPublisher<%> - (interface (SWidget<%>) - - ; SWidgetListener -> Int - ; GIVEN: An SWidgetListener - ; EFFECT: registers the listener to receive position updates from this wall. - ; RETURNS: the current x-position of the wall - register - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> WorldState -;; RETURNS: a world with a wall, a ball, and a factory -(define (initial-world) - (local - ((define the-wall (new SWall%)) - (define the-ball (new SBall% [w the-wall])) - (define the-world - (make-sworld - empty ; (list the-ball) -- the ball is now stateful - (list the-wall))) - (define the-factory - (new WidgetFactory% [wall the-wall][world the-world]))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SWorld% class - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The WidgetFactory% class - -;; accepts key events and adds SWidgetListeners to the world. - -;; We have only one of these. This is called the "singleton pattern" - -(define WidgetFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - ; KeyEvent -> Void - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (new SBall% [w wall]))] - [(key=? kev "f") - (send world add-stateful-widget (new FlashingBall% [w wall]))] - [(key=? kev "s") - (send world add-stateful-widget (new Square% [w wall]))] - )) - - ;; the Ball Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A DraggableWidget is a (new DraggableWidget% [w Wall]) - -(define DraggableWidget% - (class* object% - - ;; the methods implemented in the superclass - ; (DraggableWidget<%>) - (SWidgetListener<%>) - - ;; the methods to be supplied by each subclass - (abstract get-image ; WAS: add-to-scene - next-x-pos - next-speed - in-this?) - - - ;; the Wall that the ball should bounce off of - (init-field w) - - ;; initial values of x, y (center of widget) - (init-field [x INIT-WIDGET-X]) - (init-field [y INIT-WIDGET-Y]) - (init-field [speed INIT-WIDGET-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; object's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the widget's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected widget doesn't move. - (define/public (after-tick) - (if selected? - this - (let ((x1 (send this next-x-pos)) - (speed1 (send this next-speed))) - (begin - (set! speed speed1) - (set! x x1))))) - - ;; instead of having add-to-scene an abstract method, we keep it - ;; in the superclass, and make the differences abstract: - - (define/public (add-to-scene s) - (place-image - (send this get-image) - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (send this in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (send this in-this? mx my) - (set! selected? false) - 'error-276)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the (x, y) location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the widget ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - )) - -;; Hooks left over: these methods must be filled in from subclass. -(define DraggableWidgetHooks<%> - (interface () - - ;; Int Int -> Boolean - ;; is the given location in this widget? - in-this? - - ;; -> Int - ;; RETURNS: the next x position or speed of this widget - next-x-pos - next-speed - - ;; -> Image - ;; RETURNS: the image of this widget for display - get-image - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define SBall% - (class* - - ;; inherit method implementations from DraggableWidget% - DraggableWidget% - - ;; must implement the interface(s) of DraggableWidget% + the open - ;; hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - ;; inherit all these fields from the superclass: - - ;; the Wall that the ball should bounce off of - (inherit-field w) - - ;; initial values of x, y (center of ball) and speed: - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - ;; position of the wall, updated by update-wall-pos - (inherit-field wall-pos) - - ;; this field is local to Ball% - (field [radius 20]) - - (super-new) - - ;; make this a method instead of a function: - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - ;; the image of the ball. This could be dynamic. - (define/override (get-image) - (circle radius - "outline" - "red")) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - )) - -;; unit tests for ball: - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 110][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:speed) 50) - (check-equal? (send ball1 for-test:wall-pos) 200) - - (check-equal? (send ball1 for-test:next-speed) 50) - (check-equal? (send ball1 for-test:next-x) 160) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - -(begin-for-test - (local - ((define wall1 (new SWall% [pos 200])) - (define ball1 (new SBall% [x 160][speed 50][w wall1]))) - - (check-equal? (send ball1 for-test:x) 160) - (check-equal? (send ball1 for-test:speed) 50) - - (check-equal? (send ball1 for-test:next-x) 180) - (check-equal? (send ball1 for-test:next-speed) -50) - - (send ball1 after-tick) - - (check-equal? (send ball1 for-test:x) 180) - (check-equal? (send ball1 for-test:speed) -50) - - )) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A FlashingBall% is like a SBall%, but it displays differently: it -;; changes color on every fourth tick - -;; Constructor Template for FlashingBall% : -;; Constructor template for SBall%: -;; (new FlashingBall% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define FlashingBall% - (class* SBall% (SWidgetListener<%>) ; - - ;; here are fields of the superclass that we need. - ;; we should copy the interpretations here so we'll know what they mean. - (inherit-field radius x y selected?) - - ; how much time between color changes? - (field [color-change-interval 4]) - ; time left til next color change - (field [time-left color-change-interval]) - ; the list of possible colors, first elt is current color - (field [colors (list "red" "green")]) - - ;; the value for init-field w is sent to the superclass. - (super-new) - - ;; FlashingBall% behaves just like Ball%, except for add-to-scene. - ;; so we'll find on-tick, on-key, on-mouse methods in Ball% - - ;; Scene -> Scene - ;; RETURNS: a scene like the given one, but with the flashing ball - ;; painted on it. - ;; EFFECT: decrements time-left and changes colors if necessary - (define/override (add-to-scene s) - (begin - ;; is it time to change colors? - (if (zero? time-left) - (change-colors) - (set! time-left (- time-left 1))) - ;; call the super. The super calls (get-image) to find the - ;; image. - (super add-to-scene s))) - - ;; RETURNS: the image of this widget. - ;; NOTE: this is dynamic-- it depends on color - (define/override (get-image) - (circle radius - (if selected? "solid" "outline") - (first colors))) - - ;; -> Void - ;; EFFECT: rotate the list of colors, and reset time-left - (define (change-colors) - (set! colors (append (rest colors) (list (first colors)))) - (set! time-left color-change-interval)) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; now we'll do the same thing for Square%: - -;; Square is like Ball, but it has different geometry. - -(define Square% - (class* DraggableWidget% - - ;; must implement SWidgetListener + the open hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - (inherit-field w) ;; the Wall that the square should bounce off of - - ;; initial values of x, y (center of square) - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - (inherit-field wall-pos) - - (field [size 40]) - (field [half-size (/ size 2)]) - - (super-new) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; position of the square at the next tick - ;; STRATEGY: use the square's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - half-size - (+ x speed) - (- wall-pos half-size))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; RETURNS: the velocity of the square at the next tick - ;; STRATEGY: if the square will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< half-size (next-x-pos) (- wall-pos half-size)) - speed - (- speed))) - - (define/override (get-image) - (square size - (if selected? "solid" "outline") - "green")) - - ;; square-specific: - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (and - (<= (- x half-size) other-x (+ x half-size)) - (<= (- y half-size) other-y (+ y half-size)))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The SWall% class - -;; Constructor Template for SWall% -;; (new SWall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values - -(define SWall% - (class* object% (SWidgetPublisher<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall, otherwise can be any - ;; value. - (init-field [saved-mx 0]) - - ;; the list of registered listeners - ;; ListOf(WidgetListener<%>) - (field [listeners empty]) - - (super-new) - - ;; WidgetListener<%> -> Int - ;; EFFECT: registers the given listener - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! listeners (cons b listeners)) - pos)) - - ;; Mouse responses. How much of this could be shared using - ;; DraggableWidget? - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - this)) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - (set! selected? false)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the (x,y) location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered listeners - (define/public (after-drag mx my) - (if selected? - (begin - (set! pos (- mx saved-mx)) - (for-each - (lambda (b) (send b update-wall-pos pos)) - listeners)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/11-7-separate-files/DraggableWidget.rkt b/Examples/11-7-separate-files/DraggableWidget.rkt deleted file mode 100644 index e17791c..0000000 --- a/Examples/11-7-separate-files/DraggableWidget.rkt +++ /dev/null @@ -1,146 +0,0 @@ -#lang racket - -(require 2htdp/image) -(require "interfaces.rkt") - -;; this module defines a superclass, from which other classes will -;; inherit. So we need to provide the class itself, not a constructor -;; function. - -;; Since you can't create an object of this class, there is no -;; constructor template, either. - -;; Any subclass will have to require this file, so it will get both -;; the superclass and the additional interface. - -(provide DraggableWidget% DraggableWidgetHooks<%>) - -;; constants for all draggable widgets: - -(define INIT-WIDGET-X (/ CANVAS-HEIGHT 2)) -(define INIT-WIDGET-Y (/ CANVAS-WIDTH 3)) -(define INIT-WIDGET-SPEED 25) - -(define DraggableWidget% - (class* object% - - ;; the methods implemented in the superclass - ; (DraggableWidget<%>) - (SWidgetListener<%>) - - ;; the methods to be supplied by each subclass - (abstract get-image ; WAS: add-to-scene - next-x-pos - next-speed - in-this?) - - - ;; the Wall that the ball should bounce off of - (init-field w) - - ;; initial values of x, y (center of widget) - (init-field [x INIT-WIDGET-X]) - (init-field [y INIT-WIDGET-Y]) - (init-field [speed INIT-WIDGET-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; object's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; register this ball with the wall, and use the result as the - ;; initial value of wall-pos - (field [wall-pos (send w register this)]) - - (super-new) - - ;; Int -> Void - ;; EFFECT: updates the widget's idea of the wall's position to the - ;; given integer. - (define/public (update-wall-pos n) - (set! wall-pos n)) - - ;; after-tick : -> Void - ;; state of this ball after a tick. A selected widget doesn't move. - (define/public (after-tick) - (if selected? - this - (let ((x1 (send this next-x-pos)) - (speed1 (send this next-speed))) - (begin - (set! speed speed1) - (set! x x1))))) - - ;; instead of having add-to-scene an abstract method, we keep it - ;; in the superclass, and make the differences abstract: - - (define/public (add-to-scene s) - (place-image - (send this get-image) - x y s)) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (send this in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - this)) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (send this in-this? mx my) - (set! selected? false) - 'error-276)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the (x, y) location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'error-277)) - - ;; the widget ignores key events - (define/public (after-key-event kev) this) - - (define/public (for-test:x) x) - (define/public (for-test:speed) speed) - (define/public (for-test:wall-pos) wall-pos) - (define/public (for-test:next-speed) (next-speed)) - (define/public (for-test:next-x) (next-x-pos)) - - )) - -;; the abstract methods of DraggableWidget - -(define DraggableWidgetHooks<%> - (interface () - - ;; Int Int -> Boolean - ;; is the given location in this widget? - in-this? - - ;; -> Int - ;; RETURNS: the next x position or speed of this widget - next-x-pos - next-speed - - ;; -> Image - ;; RETURNS: the image of this widget for display - get-image - - )) diff --git a/Examples/11-7-separate-files/FlashingBall.rkt b/Examples/11-7-separate-files/FlashingBall.rkt deleted file mode 100644 index c81ab01..0000000 --- a/Examples/11-7-separate-files/FlashingBall.rkt +++ /dev/null @@ -1,75 +0,0 @@ -#lang racket - -(require "interfaces.rkt") - -(require "SBall.rkt") -(require 2htdp/image) ; for 'circle' - -(provide make-flashing-ball) - -; Wall -> SWidgetListener -(define (make-flashing-ball w) - (new FlashingBall% [w w])) - - -;; A FlashingBall% is like a SBall%, but it displays differently: it -;; changes color on every fourth tick - -;; FlashingBall% inherits from SBall%. It is an instance of the -;; 'overriding-defaults' pattern. - -;; Constructor Template for FlashingBall% : -;; (new FlashingBall% -;; [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define FlashingBall% - (class* SBall% (SWidgetListener<%>) ; - - ;; here are fields of the superclass that we need. - ;; we should copy the interpretations here so we'll know what they mean. - (inherit-field radius x y selected?) - - ; how much time between color changes? - (field [color-change-interval 4]) - ; time left til next color change - (field [time-left color-change-interval]) - ; the list of possible colors, first elt is current color - (field [colors (list "red" "green")]) - - ;; the value for init-field w is sent to the superclass. - (super-new) - - ;; FlashingBall% behaves just like Ball%, except for add-to-scene. - ;; so we'll find on-tick, on-key, on-mouse methods in Ball% - - ;; Scene -> Scene - ;; RETURNS: a scene like the given one, but with the flashing ball - ;; painted on it. - ;; EFFECT: decrements time-left and changes colors if necessary - (define/override (add-to-scene s) - (begin - ;; is it time to change colors? - (if (zero? time-left) - (change-colors) - (set! time-left (- time-left 1))) - ;; call the super. The super calls (get-image) to find the - ;; image. - (super add-to-scene s))) - - ;; RETURNS: the image of this widget. - ;; NOTE: this is dynamic-- it depends on color - (define/override (get-image) - (circle radius - (if selected? "solid" "outline") - (first colors))) - - ;; -> Void - ;; EFFECT: rotate the list of colors, and reset time-left - (define (change-colors) - (set! colors (append (rest colors) (list (first colors)))) - (set! time-left color-change-interval)) - - )) - diff --git a/Examples/11-7-separate-files/SBall.rkt b/Examples/11-7-separate-files/SBall.rkt deleted file mode 100644 index f3fc0af..0000000 --- a/Examples/11-7-separate-files/SBall.rkt +++ /dev/null @@ -1,94 +0,0 @@ -#lang racket - -(require "interfaces.rkt") - -(require "DraggableWidget.rkt") -(require 2htdp/image) ; for 'circle' - -(provide make-ball) -;; FlashingBall% inherits from SBall%, so we need to provide the class -;; as well. -(provide SBall%) - -;; Wall -> SWidgetListener -(define (make-ball w) (new SBall% [w w])) - -;; The SBall% class - -;; Constructor template for SBall%: -;; (new SBall% [x Int][y Int][speed Int] -;; [saved-mx Integer][saved-my Integer][selected? Boolean] -;; [w Wall]) - -(define SBall% - (class* - - ;; inherit method implementations from DraggableWidget% - DraggableWidget% - - ;; must implement the interface(s) of DraggableWidget% + the open - ;; hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - ;; inherit all these fields from the superclass: - - ;; the Wall that the ball should bounce off of - (inherit-field w) - - ;; initial values of x, y (center of ball) and speed: - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - ;; position of the wall, updated by update-wall-pos - (inherit-field wall-pos) - - ;; this field is local to Ball% - (field [radius 20]) - - (super-new) - - ;; make this a method instead of a function: - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: use the ball's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - radius - (+ x speed) - (- wall-pos radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if the ball will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< radius (next-x-pos) (- wall-pos radius)) - speed - (- speed))) - - ;; the image of the ball. This could be dynamic. - (define/override (get-image) - (circle radius - "outline" - "red")) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - )) - diff --git a/Examples/11-7-separate-files/SWall.rkt b/Examples/11-7-separate-files/SWall.rkt deleted file mode 100644 index b8bb55e..0000000 --- a/Examples/11-7-separate-files/SWall.rkt +++ /dev/null @@ -1,99 +0,0 @@ -#lang racket - -(require 2htdp/image) - -(require "interfaces.rkt") - -(provide make-wall) - -;; -> SWidgetPublisher -;; RETURNS: a wall at the initial position -(define (make-wall) (new SWall%)) - -(define INITIAL-WALL-POSITION 300) - -;; this should be the same as in -(define CANVAS-HEIGHT 300) - - -(define SWall% - (class* object% (SWidgetPublisher<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall, otherwise can be any - ;; value. - (init-field [saved-mx 0]) - - ;; the list of registered listeners - ;; ListOf(WidgetListener<%>) - (field [listeners empty]) - - (super-new) - - ;; WidgetListener<%> -> Int - ;; EFFECT: registers the given listener - ;; RETURNS: the current position of the wall - (define/public (register b) - (begin - (set! listeners (cons b listeners)) - pos)) - - ;; Mouse responses. How much of this could be shared using - ;; DraggableWidget? - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the (x, y) location of a button-down event - ; EFFECT: if the event is near the wall, make the wall selected. - ; STRATEGY: Cases on whether the event is near the wall - (define/public (after-button-down mx my) - (if (near-wall? mx) - (begin - (set! selected? true) - (set! saved-mx (- mx pos))) - this)) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes the Wall unselected - (define/public (after-button-up mx my) - (set! selected? false)) - - ; after-drag : Integer Integer -> Void - ; GIVEN: the (x,y) location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered listeners - (define/public (after-drag mx my) - (if selected? - (begin - (set! pos (- mx saved-mx)) - (for-each - (lambda (b) (send b update-wall-pos pos)) - listeners)) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - - diff --git a/Examples/11-7-separate-files/SWorld.rkt b/Examples/11-7-separate-files/SWorld.rkt deleted file mode 100644 index 0724c6f..0000000 --- a/Examples/11-7-separate-files/SWorld.rkt +++ /dev/null @@ -1,98 +0,0 @@ -#lang racket - -(require 2htdp/universe) ; for key=?, mouse=? -(require 2htdp/image) -(require "interfaces.rkt") - -;; The SWorld% class - -;; provide the function, not the class. -(provide make-sworld) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -;; Like the World% class in 10-4, but is stateful itself. - -;; It needs to be stable so the ball factory will know where to put -;; a new ball. - -; ListOfWidget ListOfSWidget -> World -(define (make-sworld objs sobjs) - (new SWorld% [objs objs][sobjs sobjs])) - -(define SWorld% - (class* object% (SWorld<%>) - - (init-field objs) ; ListOfWidget - (init-field sobjs) ; ListOfSWidget - - (super-new) - - (define/public (add-widget w) - (set! objs (cons w objs))) - - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define/public (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear. - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) diff --git a/Examples/11-7-separate-files/Square.rkt b/Examples/11-7-separate-files/Square.rkt deleted file mode 100644 index 6aa45f2..0000000 --- a/Examples/11-7-separate-files/Square.rkt +++ /dev/null @@ -1,84 +0,0 @@ -#lang racket - -(require "interfaces.rkt") - -(require "DraggableWidget.rkt") -(require 2htdp/image) ; for 'circle' - -(provide make-square) - -; Wall -> SWidgetListener -(define (make-square w) - (new Square% [w w])) - -;; A square is like a ball, but it has different geometry - -(define Square% - (class* DraggableWidget% - - ;; must implement SWidgetListener + the open hooks from the superclass - (SWidgetListener<%> DraggableWidgetHooks<%>) - - (inherit-field w) ;; the Wall that the square should bounce off of - - ;; initial values of x, y (center of square) - (inherit-field x y speed) - - ; is this selected? Default is false. - (inherit-field selected?) - - (inherit-field wall-pos) - - (field [size 40]) - (field [half-size (/ size 2)]) - - (super-new) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; position of the square at the next tick - ;; STRATEGY: use the square's cached copy of the wall position to - ;; set the upper limit of motion - (define/override (next-x-pos) - (limit-value - half-size - (+ x speed) - (- wall-pos half-size))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; Square-specific: turn into method - - ;; -> Integer - ;; RETURNS: the velocity of the square at the next tick - ;; STRATEGY: if the square will not be at its limit, return it - ;; unchanged. Otherwise, negate the velocity. - (define/override (next-speed) - (if - (< half-size (next-x-pos) (- wall-pos half-size)) - speed - (- speed))) - - (define/override (get-image) - (square size - (if selected? "solid" "outline") - "green")) - - ;; square-specific: - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this. - (define/override (in-this? other-x other-y) - (and - (<= (- x half-size) other-x (+ x half-size)) - (<= (- y half-size) other-y (+ y half-size)))) - - )) - - diff --git a/Examples/11-7-separate-files/WidgetFactory.rkt b/Examples/11-7-separate-files/WidgetFactory.rkt deleted file mode 100644 index 20755d1..0000000 --- a/Examples/11-7-separate-files/WidgetFactory.rkt +++ /dev/null @@ -1,57 +0,0 @@ -#lang racket - -(require 2htdp/universe) -(require "interfaces.rkt") - -;; the factory requires each of the tools for making widgets :} -(require "SBall.rkt") -(require "FlashingBall.rkt") -(require "Square.rkt") - -;; provide the function, hide the class -(provide make-widget-factory) - -;; The WidgetFactory% class - -;; accepts key events and adds SWidgetListeners to the world. -;; We have only one such class and one object of this class. This is -;; called the "singleton pattern". - -;; Wall World -> SWidget -;; RETURNS: a widget factory which will tell each widget it creates -;; about the given wall, and which will add each new widget to the -;; given world. The widget factory is itself an swidget. -(define (make-widget-factory wall world) - (new WidgetFactory% [wall wall][world world])) - - -(define WidgetFactory% - (class* object% (SWidget<%>) - - (init-field world) ; the world to which the factory adds balls - (init-field wall) ; the wall that the new balls should bounce - ; off of. - - (super-new) - - ; KeyEvent -> Void - (define/public (after-key-event kev) - (cond - [(key=? kev "b") - (send world add-stateful-widget (make-ball wall))] - [(key=? kev "f") - (send world add-stateful-widget (make-flashing-ball wall))] - [(key=? kev "s") - (send world add-stateful-widget (make-square wall))] - )) - - ;; the Factory has no other behavior - - (define/public (after-tick) this) - (define/public (after-button-down mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-drag mx my) this) - (define/public (add-to-scene s) s) - - )) - diff --git a/Examples/11-7-separate-files/extras.rkt b/Examples/11-7-separate-files/extras.rkt deleted file mode 100644 index 30b6ea3..0000000 --- a/Examples/11-7-separate-files/extras.rkt +++ /dev/null @@ -1,148 +0,0 @@ -#lang racket ; was #lang racket/base -(require (for-syntax racket/base) - racket/path - rackunit - rackunit/log) -(provide begin-for-test) -(provide provide rename-out struct-out check-error) -(provide check-location) -(provide check-within) - -(define extras-version "Wed Sep 14 08:52:19 2016") - -(printf "extras.rkt ~a~n" extras-version) - -(define-syntax (check-error stx) - (syntax-case stx () - [(_ code . msg) #`(check-exn exn:fail? (lambda () code) . msg)])) - -(define-syntax (check-within stx) - (syntax-case stx () - [(_ val1 val2 tol . msg) -; #`(check-true (<= (abs (- val1 val2)) tol) . msg) - #`(check <= (abs (- val1 val2)) tol)])) - - - -;; tests : (Parameterof (Listof (-> Void))) -;; Testing thunks in reverse order. -(define tests (make-parameter null)) - -(begin-for-syntax - ;; lifted-run-expr? : Boolean (mutable) - ;; True iff we've already appended a (run-all-tests) expr to the end - ;; of the current module. - (define lifted-run-expr? #f)) - -;; (begin-test expr ...) : module-level form -(define-syntax (begin-for-test stx) - (syntax-case stx () - [(_ expr ...) - (case (syntax-local-context) - [(module) - ;; In module (eg, defns buffer), add (run-all-tests) expr to end - ;; of module, unless previously added. - (unless lifted-run-expr? - (syntax-local-lift-module-end-declaration - #`(run-all-tests (quote #,(syntax-source stx)))) - (set! lifted-run-expr? #t)) - #'(tests (cons (lambda () (#%expression expr) ... (void)) (tests)))] - [(top-level) - ;; At top level (eg, interactions buffer), just run tests immediately. - ;; Alternative: disallow, like next case (but need different phrasing) - #'(begin (#%expression expr) ...)] - [else - (raise-syntax-error #f - "found a use of `begin-test' that is not at the top level" - stx)])])) - -;; run-all-tests : Any -> Void -;; Runs thunks in (tests) and clears (tests). -(define (run-all-tests src) - (define filename (path->string - (find-relative-path (current-directory) src - #:more-than-root? #t))) - (define ts (reverse (tests))) - (define msg - (cond [(path? src) - (format "Running tests from ~a...~n" - filename)] - [else "Running tests...~n"])) - (tests null) - (display msg) - (define start-failed+total (test-log)) - (define start-failed (car start-failed+total)) - (define start-total (cdr start-failed+total)) - (for ([t (in-list ts)]) (t)) - (define end-failed+total (test-log)) - (define failed (- (car end-failed+total) start-failed)) - (define total (- (cdr end-failed+total) start-total)) - (define (n-tests n) (format "~s ~a" n (if (= n 1) "test" "tests"))) - (cond [(zero? total) - (printf "There were no tests.\n")] - [(zero? failed) - (printf "All tests passed (~a).\n" (n-tests total))] - [else - (printf "~a failed out of ~a total in ~a.\n" - (n-tests failed) - (n-tests total) - filename)])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; check-location : String String -> Void -;; GIVEN: a 2 digit problem set number NN and the name of the file -;; being qualified. -;; EFFECT: throws an error if this file is not a directory of the form -;; pdp-*./setNN -(define (check-location NN correct-file-name) - (define path-elements (explode-path (current-directory))) - (define path-len (length path-elements)) - (define correct-folder-name (string-append "set" NN)) - (cond - [(>= path-len 2) - (define set-folder (path->string (last path-elements))) - (define pdp-folder (path->string (list-ref path-elements (- path-len 2)))) - (define set-regexp (regexp correct-folder-name)) - (define pdp-regexp (regexp "pdp-.*")) - (match* ((regexp-match? set-regexp set-folder) - (regexp-match? pdp-regexp pdp-folder)) - [(_ #f) - (error - (format - "File is in folder \"~a/~a\", which does not appear to be a local repo" - pdp-folder set-folder))] - [(#f _) - (error - (format - "File should be in a folder named ~a, but is in a folder named ~a" - correct-folder-name - set-folder))] - [(#t #t) - (printf - "~a appears to be in a correctly named folder. Running tests...~n" - correct-file-name)] - [(_ _) (void)])] - [else - (error - (format - "File should be in a folder named pdp-*/~a" - correct-folder-name))])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; for Problem Set 6, render-expr problem - -;; ListOf -> Void -;; GIVEN: A List of Strings -;; EFFECT: displays the strings in separate lines -;; RETURNS: the empty string -(define (display-strings! strs) - (if (empty? strs) (void) - (let* ((d1 (display (first strs))) - (d2 (display "\n"))) - (display-strings! (rest strs))))) - -(provide display-strings!) - - diff --git a/Examples/11-7-separate-files/interfaces.rkt b/Examples/11-7-separate-files/interfaces.rkt deleted file mode 100644 index 7d933da..0000000 --- a/Examples/11-7-separate-files/interfaces.rkt +++ /dev/null @@ -1,150 +0,0 @@ -#lang racket - -;; interfaces and constants needed by more than one class. - -(provide SWorld<%> Widget<%> SWidget<%> SWidgetListener<%> - SWidgetPublisher<%>) -(provide CANVAS-WIDTH CANVAS-HEIGHT) - -;; CONSTANTS needed by more than one class. - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - - -;; INTERFACES - -;; An SWorld is an object of any class that implements SWorld<%> - -(define SWorld<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this world to its state after a tick - after-tick - - ; Integer Integer MouseEvent-> Void - ; GIVEN: an (x,y) location - ; EFFECT: updates this world to the state that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this world to the state that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: an (x,y) location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent : KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; while we're at it, we'll rename the interfaces to reflect their -;; generic nature. - -;; Additional method for SBall% and other classes that receive messages -;; from the wall: - -(define SWidgetListener<%> - (interface (SWidget<%>) - - ; Int -> Void - ; EFFECT: updates the ball's cached value of the wall's position - update-wall-pos - - )) - -;; Additional method for classes that send messages to -;; SWidgetListeners. In our example, SWall% is the only such class. - -(define SWidgetPublisher<%> - (interface (SWidget<%>) - - ; SWidgetListener -> Int - ; GIVEN: An SWidgetListener - ; EFFECT: registers the listener to receive position updates from this wall. - ; RETURNS: the current x-position of the wall - register - - )) - diff --git a/Examples/11-7-separate-files/top.rkt b/Examples/11-7-separate-files/top.rkt deleted file mode 100644 index 0fe961f..0000000 --- a/Examples/11-7-separate-files/top.rkt +++ /dev/null @@ -1,60 +0,0 @@ -#lang racket - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - -(require "interfaces.rkt") -(require "SWall.rkt") -(require "SBall.rkt") -(require "SWorld.rkt") -(require "WidgetFactory.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;; 11-6-after-review was 838 lines. -;; When broken up into separate files, each file is <= 150 lines-- -;; much more manageable!! - -;; initial-world : -> World -;; RETURNS: a world with a wall, a ball, and a factory -(define (initial-world) - (local - ((define the-wall (make-wall)) - (define the-ball (make-ball the-wall)) - (define the-world - (make-sworld - empty ; (list the-ball) -- the ball is now stateful - (list the-wall))) - (define the-factory (make-widget-factory the-wall the-world))) - (begin - ;; put the factory in the world - (send the-world add-stateful-widget the-factory) - ;; tell the factory to start a ball - (send the-factory after-key-event "b") - the-world))) - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the world in its final state of the world -; Note: the (begin (send w ...) w) idiom -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (begin (send w after-tick) w)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (begin - (send w after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (send w after-mouse-event mx my mev) - w))))) diff --git a/Examples/11-8-mvc/ControllerFactory.rkt b/Examples/11-8-mvc/ControllerFactory.rkt deleted file mode 100644 index 1fd31c0..0000000 --- a/Examples/11-8-mvc/ControllerFactory.rkt +++ /dev/null @@ -1,58 +0,0 @@ -#lang racket - -(require "WidgetWorks.rkt") -(require "Interfaces.rkt") -(require "VelocityController.rkt") -(require "PositionController.rkt") -(require 2htdp/universe) - -(provide make-controller-factory) - -;; make-controller-factory : Container Model -> SWidget -(define (make-controller-factory c m) - (new ControllerFactory% [c c][m m])) - -;; Contstructor Template for ControllerFactory%: -;; (new ControllerFactory% [c c][m m])) - -(define ControllerFactory% - (class* object% (SWidget<%>) - - ; the container in which the controllers will live - (init-field c) ; Container - - ; the model to which the controllers will be connected - (init-field m) ; Model - - (super-new) - - ; KeyEvent -> Void - (define/public (after-key-event kev) - (cond - [(key=? kev "v") (add-viewer make-velocity-controller)] - [(key=? kev "p") (add-viewer make-position-controller)] - )) - - - ;; (Model -> Controller) -> Void - (define/public (add-viewer make-viewer) - (send c add-stateful-widget (make-viewer m))) - - ;; the factory is invisible - (define/public (add-to-scene s) s) - - ;; the factory doesn't respond to any other events - (define/public (after-tick) 'controller-factory-after-tick-trap) - (define/public (after-button-down mx my) - 'controller-factory-after-button-down-trap) - (define/public (after-drag mx my) - 'controller-factory-after-drag-trap) - (define/public (after-move mx my) - 'controller-factory-after-move-trap) - (define/public (after-button-up mx my) - 'controller-factory-after-button-up-trap) - - )) - - - diff --git a/Examples/11-8-mvc/Interfaces.rkt b/Examples/11-8-mvc/Interfaces.rkt deleted file mode 100644 index e6cd890..0000000 --- a/Examples/11-8-mvc/Interfaces.rkt +++ /dev/null @@ -1,88 +0,0 @@ -#lang racket - -;; interfaces for MVC example - -(require "WidgetWorks.rkt") - -(provide Controller<%> Model<%>) - -;; structs for model command language -(provide - (struct-out set-position) - (struct-out incr-velocity) - (struct-out report-position) - (struct-out report-velocity)) - -;; A Controller is an object of any class that implements -;; Controller<%> - -;; There will be several such classes, and there may be several -;; objects of each such class. - -(define Controller<%> - (interface (SWidget<%>) - - ;; Signal -> Void - ;; receive a signal from the model and adjust controller - ;; accordingly - receive-signal - - )) - -;; A Model is an object of any class that implements Model<%>. Models -;; will receive signals from the Container, so they must implement the -;; SWidget<%> interface in order to do so. - -(define Model<%> - (interface (SWidget<%>) - - ;; Controller -> Void - ;; Registers the given controller to receive signal - register - - ;; Command -> Void - ;; Executes the given command - execute-command -)) - -;; CONTROLLER/MODEL PROTOCOL: - -;; As soon as a controller registers with the model, the model sends -;; the controller a pair of Signals so the controller will know the -;; current state of the model. - -;; The controller then sends the model commands, which the model is -;; supposed to execute. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; DATA DEFINITIONS FOR COMMUNICATING WITH MODEL - -;; A Command is one of -;; -- (make-set-position n) -;; -- (make-incr-velocity dv) - -;; A Signal is one of -;; -- (make-report-position n) -;; -- (make-report-velocity v) - -;; n, v, dv are all Reals. - -;; provide the structs for Command and Signal -;; the syntax of provide in #lang racket has more options in it. - - -(define-struct set-position (pos) #:transparent) -(define-struct incr-velocity (dv) #:transparent) -(define-struct report-position (pos) #:transparent) -(define-struct report-velocity (v) #:transparent) - - - - - - - - - - diff --git a/Examples/11-8-mvc/Model.rkt b/Examples/11-8-mvc/Model.rkt deleted file mode 100644 index b742c32..0000000 --- a/Examples/11-8-mvc/Model.rkt +++ /dev/null @@ -1,152 +0,0 @@ -#lang racket - -;; the model consists of a particle, bouncing with its center from x=0 -;; to x=200. It accepts commands and reports when its status changes - -(require rackunit) -(require "extras.rkt") -(require "interfaces.rkt") - -(provide make-model) - -;; -> Model -(define (make-model) (new Model%)) - -;; Constructor template for Model%: -;; (new Model%) - -(define Model% - (class* object% (Model<%>) - - ;; boundaries of the field - (field [lo 0]) - (field [hi 200]) - - ;; position and velocity of the object - (init-field [x (/ (+ lo hi) 2)]) - (init-field [v 0]) - - ; ListOfController. The list of registered controllers - (init-field [controllers empty]) - - (super-new) - - ;; -> Void - ;; moves the object by v. - ;; limits the resulting x to [0, 200]. - ;; publishes x at every tick - ;; publishes velocity only when it changes - (define/public (after-tick) - (set! x (within-limits lo (+ x v) hi)) - (publish-position) - (if (or (= x hi) (= x lo)) - (begin - (set! v (- v)) - (publish-velocity)) - "somebody tried to use the value of model.rkt after-tick")) - - (define (within-limits lo val hi) - (max lo (min val hi))) - - ;; Controller -> Void - ;; register the new controller and send it some data - (define/public (register c) - (begin - (set! controllers (cons c controllers)) - (send c receive-signal (make-report-position x)) - (send c receive-signal (make-report-velocity v)))) - - ;; Command -> Void - ;; decodes the command, executes it, and sends updates to the - ;; controllers. - (define/public (execute-command cmd) - (cond - [(set-position? cmd) - (begin - (set! x (set-position-pos cmd)) - (publish-position))] - [(incr-velocity? cmd) - (begin - (set! v (+ v (incr-velocity-dv cmd))) - (publish-velocity))])) - - ;; report position or velocity to each controller: - - ;; -> Void - (define (publish-position) - (let ((msg (make-report-position x))) - (for-each - (lambda (obs) (send obs receive-signal msg)) - controllers) - )) - - ;; -> Void - (define (publish-velocity) - (let ((msg (make-report-velocity v))) - (for-each - (lambda (obs) (send obs receive-signal msg)) - controllers))) - - ;; The model responds to after-tick, but not to any of the other - ;; SWidget messages - (define/public (after-button-down mx my) 'trap) - (define/public (after-button-up mx my) 'trap) - (define/public (after-drag mx my) 'trap) - (define/public (after-move mx my) 'trap) - (define/public (after-key-event kev) 'trap) - (define/public (add-to-scene s) s) - - ;; test methods - (define/public (for-test:get-x) x) - (define/public (for-test:get-v) v) - - )) - -;;; tests - -;; check to see if the model responds to incr-velocity commands (it -;; does) and to after-tick messages - -(begin-for-test - - (let* - ((m (make-model))) - (begin - (check-equal? (send m for-test:get-x) 100) - (check-equal? (send m for-test:get-v) 0) - (send m after-tick) - (check-equal? (send m for-test:get-x) 100) - (check-equal? (send m for-test:get-v) 0) - - (send m execute-command (make-incr-velocity 2)) - (check-equal? (send m for-test:get-v) 2) - - (send m after-tick) - (check-equal? (send m for-test:get-x) 102) - (check-equal? (send m for-test:get-v) 2) - - (send m after-tick) - (check-equal? (send m for-test:get-x) 104) - (check-equal? (send m for-test:get-v) 2) - - ))) - -;; m is definitely responding to after-tick messages. Is it not -;; getting the after-tick messages from big-bang? - -;; Ans: yes, that's the problem: In top.rkt, I created the model, but -;; never added it to the Container (duh!) - - - - - - - - - - - - - - diff --git a/Examples/11-8-mvc/PositionController.rkt b/Examples/11-8-mvc/PositionController.rkt deleted file mode 100644 index 907c2c1..0000000 --- a/Examples/11-8-mvc/PositionController.rkt +++ /dev/null @@ -1,169 +0,0 @@ -#lang racket - -;; displays as an outline rectangle with text showing the x -;; coordinate and velocity of the particle. - -;; the rectangle is draggable - -;; +,- increments or decrements location of the particle by 5 - -(require 2htdp/image) -(require 2htdp/universe) -(require "interfaces.rkt") - -(provide make-position-controller) - -;; make-position-controller : Model -> Controller -;; GIVEN: a model m -;; RETURNS: A position controller for m - -(define (make-position-controller m) - (new PositionController% [model m])) - - -;; Constructor template for PositionController% -;; (new PositionController% [model Model]) - -(define PositionController% - (class* object% (Controller<%>) - - (init-field model) ; the model - - ; Position of the center of the controller - ; both of these are NonNegInts. - (init-field [x 150] [y 100]) - - ; width and height of the controller. Both PosInts. - (init-field [width 120][height 50]) - - (field [half-width (/ width 2)]) - (field [half-height (/ height 2)]) - - ;; controller's cache of the position and velocity of the - ;; particle. - ;; both Reals. - (field [particle-x 0]) - (field [particle-v 0]) - - ;; fields for dragging - ;; if selected? then position of last button-down relative to - ;; center of viewer; else any value - (field [selected? false]) - (field [saved-mx 0]) - (field [saved-my 0]) - - (super-new) - - ;; at initialization, register this controller with the model - (send model register this) - - ;; Signal -> Void - ;; decodes signal and updates local data - (define/public (receive-signal sig) - (cond - [(report-position? sig) - (set! particle-x (report-position-pos sig))] - [(report-velocity? sig) - (set! particle-v (report-velocity-v sig))])) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; EFFECT: makes the viewer selected - ; The viewer stays selected until a button down somewhere else - ; STRATEGY: Cases on whether the event is in this object - (define/public (after-button-down mx my) - (if (in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - (set! selected? false))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: ignored - - (define/public (after-button-up mx my) 'ignored) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether this is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'position-controller-after-drag-value)) - - ;; the position controller doesn't respond to mouse move events - (define/public (after-move mx my) - 'position-controller-after-move-value) - - ;; Int Int -> Boolean - (define (in-this? other-x other-y) - (and - (<= (- x half-width) other-x (+ x half-width)) - (<= (- y half-height) other-y (+ y half-height)))) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - ;; STRATEGY: place the image centered at x y - - (define/public (add-to-scene scene) - (place-image (viewer-image) x y scene)) - - ;; the controller doesn't respond to ticks - (define/public (after-tick) - 'position-controller-after-tick-value) - - ;; KeyEvent -> Void - ;; interpret +,- as commands to the model - ;; +/- alter position of the particle - (define/public (after-key-event kev) - (if selected? - (cond - [(key=? "+" kev) - (send model execute-command - (make-set-position (+ particle-x 5)))] - [(key=? "-" kev) - (send model execute-command - (make-set-position (- particle-x 5)) - )]) - 'position-controller-after-key-event-value)) - - ;; -> Image - ;; RETURNS: the image of the viewer - ;; STRATEGY: assemble the image from the data and rectangle - (define (viewer-image) - (let ((the-data-image (data-image))) - (overlay - the-data-image - (rectangle - (max width (+ (image-width the-data-image) 10)) - (max height (+ (image-height the-data-image) 10)) - "outline" - (current-color))))) - - ;; -> Image - (define (data-image) - (above - (text "+/- : Change position" 10 "black") - (text (string-append - "X = " - (number->string particle-x) - " Velocity = " - (number->string particle-v)) - 12 - "black"))) - - (define (current-color) - (if selected? "red" "black")) - - )) - diff --git a/Examples/11-8-mvc/README b/Examples/11-8-mvc/README deleted file mode 100644 index e2b2219..0000000 --- a/Examples/11-8-mvc/README +++ /dev/null @@ -1,11 +0,0 @@ -Read these files in the following order: - -Interfaces.rkt -Model.rkt -PositionController.rkt -VelocityController.rkt -ControllerFactory.rkt -top.rkt - -{should we just use WidgetWorks.rkt??} -{rename filenames to lower case} diff --git a/Examples/11-8-mvc/Reporter.rkt b/Examples/11-8-mvc/Reporter.rkt deleted file mode 100644 index eb5d98e..0000000 --- a/Examples/11-8-mvc/Reporter.rkt +++ /dev/null @@ -1,36 +0,0 @@ -#lang racket - -(require "interfaces.rkt") - -(provide make-reporter) - -;; Model -> Reporter -(define (make-reporter m) - (new Reporter% [model m])) - -;; set up a little object that just receives signals from a model. - -(define Reporter% - (class* object% () ;; too lazy to write a Reporter<%> interface - (init-field model) - ;; the position and velocity reported by the model - (field [x 0][v 0]) - (super-new) - (send model register this) - - ;; Signal -> Void - ;; decodes signal and updates local data - (define/public (receive-signal sig) - (cond - [(report-position? sig) - (set! x (report-position-pos sig))] - [(report-velocity? sig) - (set! v (report-velocity-v sig))])) - - (define/public (model-x) x) - (define/public (model-v) v) - - (define/public (model-state) - (list 'Position: x 'Velocity: v)) - - )) diff --git a/Examples/11-8-mvc/VelocityController.rkt b/Examples/11-8-mvc/VelocityController.rkt deleted file mode 100644 index 80ee896..0000000 --- a/Examples/11-8-mvc/VelocityController.rkt +++ /dev/null @@ -1,210 +0,0 @@ -#lang racket - -;; displays as an outline rectangle with text showing the x -;; coordinate and velocity of the particle. - -;; the rectangle is draggable - -;; +,- increments or decrements the speed of the particle - -(require 2htdp/image) -(require 2htdp/universe) -(require "interfaces.rkt") - -(provide make-velocity-controller) - -;; make-velocity-controller : Model -> Controller -;; GIVEN: a model m -;; RETURNS: A velocity controller for m - -(define (make-velocity-controller m) - (new VelocityController% [model m])) - - -;; Constructor template for VelocityController% -;; (new VelocityController% [model Model]) - -(define VelocityController% - (class* object% (Controller<%>) - - (init-field model) ; the model - - ; Position of the center of the controller - ; both of these are NonNegInts. - (init-field [x 150] [y 100]) - - ; width and height of the controller. Both PosInts. - (init-field [width 120][height 50]) - - (field [half-width (/ width 2)]) - (field [half-height (/ height 2)]) - - ;; controller's cache of the position and velocity of the - ;; particle. - ;; both Reals. - (field [particle-x 0]) - (field [particle-v 0]) - - ;; fields for dragging - ;; if selected? then position of last button-down relative to - ;; center of viewer; else any value - (field [selected? false]) - (field [saved-mx 0]) - (field [saved-my 0]) - - (super-new) - - ;; at initialization, register this controller with the model - (send model register this) - - ;; Signal -> Void - ;; decodes signal and updates local data - (define/public (receive-signal sig) - (cond - [(report-position? sig) - (set! particle-x (report-position-pos sig))] - [(report-velocity? sig) - (set! particle-v (report-velocity-v sig))])) - - ; after-button-down : Integer Integer -> Void - ; GIVEN: the location of a button-down event - ; EFFECT: makes the viewer selected - ; The viewer stays selected until a button down somewhere else - ; STRATEGY: Cases on whether the event is in this object - (define/public (after-button-down mx my) - (if (in-this? mx my) - (begin - (set! selected? true) - (set! saved-mx (- mx x)) - (set! saved-my (- my y))) - (set! selected? false))) - - ; after-button-up : Integer Integer -> Void - ; GIVEN: the (x,y) location of a button-up event - ; EFFECT: makes this unselected - - (define/public (after-button-up mx my) 'ignored) - - - ; after-drag : Integer Integer -> Void - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether this is selected. - ; If it is selected, move it so that the vector from its position to - ; the drag event is equal to saved-mx. Report the new position to - ; the registered balls. - - (define/public (after-drag mx my) - (if selected? - (begin - (set! x (- mx saved-mx)) - (set! y (- my saved-my))) - 'velocity-controller-after-drag-value)) - - ;; the velocity controller doesn't respond to mouse move events - (define/public (after-move mx my) - 'velocity-controller-after-move-value) - - ;; Int Int -> Boolean - (define (in-this? other-x other-y) - (and - (<= (- x half-width) other-x (+ x half-width)) - (<= (- y half-height) other-y (+ y half-height)))) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - ;; STRATEGY: place the image centered at x y - - (define/public (add-to-scene scene) - (place-image (viewer-image) x y scene)) - - ;; the controller doesn't respond to ticks - (define/public (after-tick) - 'velocity-controller-after-tick-value) - - ;; KeyEvent -> Void - ;; interpret +,- as commands to the model - ;; +/- alter velocity of the particle - (define/public (after-key-event kev) - (if selected? - (cond - [(key=? "+" kev) - (send model execute-command (make-incr-velocity 1))] - [(key=? "-" kev) - (send model execute-command (make-incr-velocity -1))]) - 3456)) - - ;; -> Image - ;; RETURNS: the image of the viewer - ;; STRATEGY: assemble the image from the data and rectangle - (define (viewer-image) - (let ((the-data-image (data-image))) - (overlay - the-data-image - (rectangle - (max width (+ (image-width the-data-image) 10)) - (max height (+ (image-height the-data-image) 10)) - "outline" - (current-color))))) - - ;; -> Image - (define (data-image) - (above - (text "+/- : Change velocity" 10 "black") - (text (string-append - "X = " - (number->string particle-x) - " Velocity = " - (number->string particle-v)) - 12 - "black"))) - - (define (current-color) - (if selected? "red" "black")) - - (define/public (for-test:select) - (set! selected? true)) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; for testing, we'll create a model and a controller for it. -;;; We'll send some messages to the controller, and see if the -;;; model gets updated appropriately. - -(require rackunit) -(require "extras.rkt") -(require "Model.rkt") - -(begin-for-test - - (let* - ((m (make-model)) - (c (make-velocity-controller m))) - (begin - (check-equal? (send m for-test:get-x) 100) - (check-equal? (send m for-test:get-v) 0) - - ;; send m a make-incr-velocity command directly, and see if it - ;; responds. - (send m execute-command (make-incr-velocity 2)) - (check-equal? (send m for-test:get-v) 2) - - ;; now send the controller "+". It should send m a - ;; make-incr-velocity command. See if that causes the model to - ;; respond properly. - (send c for-test:select) - (send c after-key-event "+") - (check-equal? (send m for-test:get-v) 3) - - ;; does m respond to an after-tick message (yes). - (send m after-tick) - (check-equal? (send m for-test:get-x) 103) - - ))) - - - - diff --git a/Examples/11-8-mvc/WidgetWorks.rkt b/Examples/11-8-mvc/WidgetWorks.rkt deleted file mode 100644 index fd7266e..0000000 --- a/Examples/11-8-mvc/WidgetWorks.rkt +++ /dev/null @@ -1,219 +0,0 @@ -#lang racket - -(require 2htdp/universe) -(require 2htdp/image) - -(provide - container-init - Container<%> - Widget<%> - SWidget<%>) - -;; A Container is an object of any class that implements Container<%>. -;; In Widgetworks, there is only one such class. - -(define Container<%> - (interface () - - ; Widget -> Void - ; GIVEN: A widget - ; EFFECT: add the given widget to the world - add-widget - - ; SWidget -> Void - ; GIVEN: A stateful widget - ; EFFECT: add the given widget to the world - add-stateful-widget - - ; PosReal -> Void - ; GIVEN: a framerate, in secs/tick - ; EFFECT: runs this world at the given framerate - run - - )) - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - after-move - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; An SWidget is an object of any class that implements the SWidget<%> -;; interface. - -;; A SWidget is like a Widget, but it is stable (stateful). - -(define SWidget<%> - (interface () - - ; -> Void - ; GIVEN: no arguments - ; EFFECT: updates this widget to the state it should have - ; following a tick. - after-tick - - ; Integer Integer -> Void - ; GIVEN: a location - ; EFFECT: updates this widget to the state it should have - ; following the specified mouse event at the given location. - after-button-down - after-button-up - after-drag - after-move - - ; KeyEvent -> Void - ; GIVEN: a key event - ; EFFECT: updates this widget to the state it should have - ; following the given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -; ListOfWidget ListOfStatefulWidget -> Container -(define (container-init w h) - (new WWContainer% [canvas-width w][canvas-height h])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; note: WWContainer% is NOT provided. Only Container<%> is provided. - -(define WWContainer% - (class* object% (Container<%>) - - (init-field canvas-width) - (init-field canvas-height) - - (init-field [objs empty]) ; ListOfWidget - (init-field [sobjs empty]) ; ListOfSWidget - - (field [EMPTY-CANVAS (empty-scene canvas-width canvas-height)]) - - (super-new) - - ; run : PosReal -> World - ; GIVEN: a frame rate, in secs/tick - ; EFFECT: runs this world at the given frame rate - ; RETURNS: the world in its final state of the world - ; Note: the (begin (send w ...) w) idiom - - (define/public (run rate) - (big-bang this - (on-tick - (lambda (w) (begin (after-tick) w)) - rate) - (on-draw - (lambda (w) (to-scene))) - (on-key - (lambda (w kev) - (begin - (after-key-event kev) - w))) - (on-mouse - (lambda (w mx my mev) - (begin - (after-mouse-event mx my mev) - w))))) - - ;; Widget -> Void - (define/public (add-widget w) - (set! objs (cons w objs))) - - ;; Widget -> Void - (define/public (add-stateful-widget w) - (set! sobjs (cons w sobjs))) - - ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void - ;; this means that fn must satisfy both (Widget -> Widget) and - ;; (SWidget -> Void) - (define (process-widgets fn) - (begin - (set! objs (map fn objs)) - (for-each fn sobjs))) - - ;; after-tick : -> Void - ;; Use map on the Widgets in this World; use for-each on the - ;; stateful widgets - - (define (after-tick) - (process-widgets - (lambda (obj) (send obj after-tick)))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets and SWidgets in this World - ;; Note: the append is inefficient, but clear. We expect that - ;; most of the widgets in the world will be stateful. - - (define (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (append objs sobjs))) - - ;; after-key-event : KeyEvent -> Void - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define (after-key-event kev) - (process-widgets - (lambda (obj) (send obj after-key-event kev)))) - - ;; after-mouse-event : Nat Nat MouseEvent -> Void - ;; STRATGY: Cases on mev - (define (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (process-widgets - (lambda (obj) (send obj after-button-down mx my)))) - - - (define (world-after-button-up mx my) - (process-widgets - (lambda (obj) (send obj after-button-up mx my)))) - - - (define (world-after-drag mx my) - (process-widgets - (lambda (obj) (send obj after-drag mx my)))) - - )) diff --git a/Examples/11-8-mvc/extras.rkt b/Examples/11-8-mvc/extras.rkt deleted file mode 100644 index bcfe89b..0000000 --- a/Examples/11-8-mvc/extras.rkt +++ /dev/null @@ -1,141 +0,0 @@ -#lang racket ; was #lang racket/base -(require (for-syntax racket/base) - racket/path - rackunit - rackunit/log) -(provide begin-for-test) -(provide provide rename-out struct-out check-error) -(provide check-location) - -(define extras-version "Wed Oct 15 13:09:22 2014") - -(printf "extras.rkt ~a~n" extras-version) - -(define-syntax (check-error stx) - (syntax-case stx () - [(_ code . msg) #`(check-exn exn:fail? (lambda () code) . msg)])) - - - -;; tests : (Parameterof (Listof (-> Void))) -;; Testing thunks in reverse order. -(define tests (make-parameter null)) - -(begin-for-syntax - ;; lifted-run-expr? : Boolean (mutable) - ;; True iff we've already appended a (run-all-tests) expr to the end - ;; of the current module. - (define lifted-run-expr? #f)) - -;; (begin-test expr ...) : module-level form -(define-syntax (begin-for-test stx) - (syntax-case stx () - [(_ expr ...) - (case (syntax-local-context) - [(module) - ;; In module (eg, defns buffer), add (run-all-tests) expr to end - ;; of module, unless previously added. - (unless lifted-run-expr? - (syntax-local-lift-module-end-declaration - #`(run-all-tests (quote #,(syntax-source stx)))) - (set! lifted-run-expr? #t)) - #'(tests (cons (lambda () (#%expression expr) ... (void)) (tests)))] - [(top-level) - ;; At top level (eg, interactions buffer), just run tests immediately. - ;; Alternative: disallow, like next case (but need different phrasing) - #'(begin (#%expression expr) ...)] - [else - (raise-syntax-error #f - "found a use of `begin-test' that is not at the top level" - stx)])])) - -;; run-all-tests : Any -> Void -;; Runs thunks in (tests) and clears (tests). -(define (run-all-tests src) - (define filename (path->string - (find-relative-path (current-directory) src - #:more-than-root? #t))) - (define ts (reverse (tests))) - (define msg - (cond [(path? src) - (format "Running tests from ~a...~n" - filename)] - [else "Running tests...~n"])) - (tests null) - (display msg) - (define start-failed+total (test-log)) - (define start-failed (car start-failed+total)) - (define start-total (cdr start-failed+total)) - (for ([t (in-list ts)]) (t)) - (define end-failed+total (test-log)) - (define failed (- (car end-failed+total) start-failed)) - (define total (- (cdr end-failed+total) start-total)) - (define (n-tests n) (format "~s ~a" n (if (= n 1) "test" "tests"))) - (cond [(zero? total) - (printf "There were no tests.\n")] - [(zero? failed) - (printf "All tests passed (~a).\n" (n-tests total))] - [else - (printf "~a failed out of ~a total in ~a.\n" - (n-tests failed) - (n-tests total) - filename)])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; check-location : String String -> Void -;; GIVEN: a 2 digit problem set number NN and the name of the file -;; being qualified. -;; EFFECT: throws an error if this file is not a directory of the form -;; pdp-*./setNN -(define (check-location NN correct-file-name) - (define path-elements (explode-path (current-directory))) - (define path-len (length path-elements)) - (define correct-folder-name (string-append "set" NN)) - (cond - [(>= path-len 2) - (define set-folder (path->string (last path-elements))) - (define pdp-folder (path->string (list-ref path-elements (- path-len 2)))) - (define set-regexp (regexp correct-folder-name)) - (define pdp-regexp (regexp "pdp-.*")) - (match* ((regexp-match? set-regexp set-folder) - (regexp-match? pdp-regexp pdp-folder)) - [(_ #f) - (error - (format - "File is in folder \"~a/~a\", which does not appear to be a local repo" - pdp-folder set-folder))] - [(#f _) - (error - (format - "File should be in a folder named ~a, but is in a folder named ~a" - correct-folder-name - set-folder))] - [(#t #t) - (printf - "~a appears to be in a correctly named folder. Running tests...~n" - correct-file-name)] - [(_ _) (void)])] - [else - (error - (format - "File should be in a folder named pdp-*/~a" - correct-folder-name))])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; for Problem Set 6, render-expr problem - -;; ListOf -> Void -;; GIVEN: A List of Strings -;; EFFECT: displays the strings in separate lines -;; RETURNS: the empty string -(define (display-strings! strs) - (if (empty? strs) (void) - (let* ((d1 (display (first strs))) - (d2 (display "\n"))) - (display-strings! (rest strs))))) - -(provide display-strings!) - - diff --git a/Examples/11-8-mvc/top.rkt b/Examples/11-8-mvc/top.rkt deleted file mode 100644 index 6a34bc8..0000000 --- a/Examples/11-8-mvc/top.rkt +++ /dev/null @@ -1,18 +0,0 @@ -#lang racket - -(require "WidgetWorks.rkt") -(require "Interfaces.rkt") -(require "Model.rkt") -(require "ControllerFactory.rkt") - -;; run with (run 0.5) - -;; create a container, install a factory, and run. - -(define (run rate) - (let ((c (container-init CANVAS-WIDTH CANVAS-HEIGHT)) - (m (make-model))) - (begin - (send c add-stateful-widget m) - (send c add-stateful-widget (make-controller-factory c m)) - (send c run rate)))) diff --git a/Examples/11-interface-proposal.rkt b/Examples/11-interface-proposal.rkt deleted file mode 100644 index 0bd7192..0000000 --- a/Examples/11-interface-proposal.rkt +++ /dev/null @@ -1,96 +0,0 @@ -;; Here's a proposal for talking about interfaces. - -;; A class has two interfaces: -;; -- the methods it provides (perhaps with the help of its -;; superclasses) -;; -- the methods it requires (from its subclasses). - -;; Unfortunately, the Racket object system only allows us to document -;; the former; the latter is implicit in the list of (abstract ..) -;; declarations in the superclass. - -;; The concept is that the superclass provides services to its -;; subclasses; only the instantiable subclass provides the full interface. - -;; Under this plan, the superclass wouldn't claim to implement -;; SBall<%>; only the instantiable subclasses do so. - -;; Need to change L11.2 slide 10 to remove (abstract add-to-scene). -;; L11.2 slide 17 needs to change to reflect the new interface. - -;; note that add-to-scene is in SBall<%> but not in DWprovides<%> - -(define DWprovides<%> - (interface () - update-wall-pos - after-tick - after-button-down - after-button-up - after-drag)) - -(define DWHooks<%> - (interface () - next-x-pos - next-speed - in-this?)) - -(define DraggableWidget% - (class* object% (DWprovides%) - - (abstract - next-x-pos - next-speed - in-this?) - - (define/public (update-wall-pos n) ...) - - (define/public (after-tick) - (if selected? - this - (let ((x1 (send this next-x-pos)) - (speed1 (send this next-speed))) - ...))) - - ;; to be supplied by each subclass - (abstract next-x-pos) - (abstract next-speed) - - ; NOT an abstract method of this class - ; (abstract add-to-scene) - - ; after-button-down : Integer Integer -> Void - (define/public (after-button-down mx my) - (if (send this in-this? mx my) ...)) - - ;; to be supplied by the subclass - (abstract in-this?) - - ; after-button-up : Integer Integer -> Void - (define/public (after-button-up mx my) - (if (send this in-this? mx my) ...)) - - ; after-drag : Integer Integer -> Void - (define/public (after-drag mx my) ...) - - )) - -(define Ball% - (class* - - ;; inherit method implementations from DraggableWidget% - DraggableWidget% - - ;; all the methods of SBall<%> are either inherited from - ;; DraggableWidget% or defined locally. - ;; Since we inherit from DraggableWidget%, we need to provide its - ;; hooks - (SBall<%> DWHooks<%>) - - (define/public (add-to-scene ...) ...) - - (define/override (next-x-pos) ...) - (define/override (next-speed) ...) - (define/override (in-this? other-x other-y) ...) - - )) - diff --git a/Examples/12-interp/datatypes.rkt b/Examples/12-interp/datatypes.rkt deleted file mode 100644 index 43c68f0..0000000 --- a/Examples/12-interp/datatypes.rkt +++ /dev/null @@ -1,92 +0,0 @@ -#lang racket - -(require rackunit) -(require "extras.rkt") - -;; Data Definitions for Programs and Values. - -(provide (struct-out program) - (struct-out fcn-decl) - (struct-out const-decl) - (struct-out const) - (struct-out variable) - (struct-out ifzero) - (struct-out diff) - (struct-out call) - decl-name - decl-value) - -;; language: - -#| -Rough concrete syntax: - -program ::= decl* expr -decl ::= name arg* expr -decl ::= name number -expr ::= number | variable | if expr expr expr - | (expr - expr) - | (name expr expr ...) ; function call - -|# - -;; A Program is a (make-program ListOfDecl Expr) - -;; A Decl is one of -;; -- (make-fcn-decl Name ListOfName Expr) -;; -- (make-const-decl Name Number) - -;; An Expr is one of -;; -- (make-const Number) -;; -- (make-variable Symbol) -;; -- (make-ifzero Expr Expr Expr) -;; -- (make-diff Expr Expr) -;; -- (make-call Name ListOfExpr) - -;; A Value is one of -;; -- Number -;; -- (make-fcn-decl Name ListOfName Expr) - -;; A Name is a Symbol - -(define-struct program (decls main)) -(define-struct fcn-decl (name args body)) -(define-struct const-decl (name value)) -(define-struct const (value)) -(define-struct variable (name)) -(define-struct diff (expr1 expr2)) -(define-struct ifzero (test then else)) -(define-struct call (name exprs)) - -;; We'll put a couple of help functions for declarations here: - -;; Decl -> Name -(define (decl-name d) - (cond - [(fcn-decl? d) (fcn-decl-name d)] - [(const-decl? d) (const-decl-name d)])) - -;; Decl -> Value -(define (decl-value d) - (cond - [(fcn-decl? d) d] - [(const-decl? d) (const-decl-value d)])) - -(begin-for-test - - (local - ((define decl1 (make-fcn-decl 'f '(x y) - (diff - (make-variable 'x) - (make-variable 'y)))) - (define decl2 (make-const-decl 'u 3))) - (check-equal? (decl-name decl1) 'f) - (check-equal? (decl-name decl2) 'u) - (check-equal? (decl-value decl1) decl1) - (check-equal? (decl-value decl2) 3)) - -) - - - - diff --git a/Examples/12-interp/environments.rkt b/Examples/12-interp/environments.rkt deleted file mode 100644 index c7baab8..0000000 --- a/Examples/12-interp/environments.rkt +++ /dev/null @@ -1,195 +0,0 @@ -#lang racket - -;; Environments for looking up values and procedures - -(require rackunit) -(require "extras.rkt") - -(require "datatypes.rkt") - -;;; ================================================================ -;;; INTERFACE -;;; ================================================================ - -(provide empty-env) ; : Env -(provide make-env) ; : ListOfName ListOfValue Environment -> Environment -(provide env-lookup) ; : Env Name -> Value - -;; Information: an environment is a partial map from names to values. - -;; Interpretation of interface functions: - -;; empty-env represents the empty environment. -;; Looking up any name in the empty environment raises an -;; error. - -;; env-lookup looks up the given name in the given environment - -;; make-env extends an environment with a set of new associations -;; between names and values. - -;; EXAMPLES: - -;(define env1 (make-env -; (list 'x 'y 'z 'u) -; (list 3 4 5 7) -; empty-env)) - -;; defines env1 to be a representation of the partial function - -;; {(x,3),(y,4),(z,5),(u,7)} - -;(define env2 (make-env -; (list 'v 'y) -; (list 8 9) -; env1)) - - -;; defines env2 to be a representation of the partial function that is -;; just like env1, except that if you ask it about v, you get 8, and if -;; you ask it about y, you get 9. That is to say, env2 is a -;; representation of the partial function - -;; {(v,8),(y,9),(x,3),(z,5),(u,7)} - -;; Note that the "old value" of y is overrridden. - -;; TESTS: - -(begin-for-test - - (local - ((define env1 (make-env - (list 'x 'y 'z 'u) - (list 3 4 5 7) - empty-env)) - (define env2 (make-env - (list 'v 'y) - (list 8 9) - env1))) - - (check-error (env-lookup empty-env 'x)) - - (check-equal? (env-lookup env1 'x) 3) - (check-equal? (env-lookup env1 'y) 4) - (check-equal? (env-lookup env1 'z) 5) - (check-equal? (env-lookup env1 'u) 7) - (check-error (env-lookup env1 'v)) ; some other name - - - (check-equal? (env-lookup env2 'x) 3) - (check-equal? (env-lookup env2 'y) 9) - (check-equal? (env-lookup env2 'z) 5) - (check-equal? (env-lookup env2 'u) 7) - (check-equal? (env-lookup env2 'v) 8) - (check-error (env-lookup env2 'w)) ; some other name - - )) - - -;;; ================================================================ -;;; IMPLEMENTATION -;;; ================================================================ - -;;; You shouldn't have to look at the implementation! - -;; We represent an environment by a list of bindings. - -;; A Binding (Bnd) is a (list Name Value) -(define (make-binding n v) (list n v)) -(define (binding-name bnd) (first bnd)) -(define (binding-value bnd) (second bnd)) - - -;; An Environment (Env) is one of -;; -- empty -;; Interp: the environment that is undefined for any name. -;; -- (cons (list Name Value) Environment) -;; Interp: (cons (list n v) env) represents the environment that -;; is just like env, but if you ask it about n, it returns v. - -;; empty-env : Env -(define empty-env empty) - -;; make-env : ListOfName ListOfValue Environment-> Environment -;; GIVEN: a list of names, a list of values, and an environment -;; WHERE: the two lists have the same length and there are no -;; duplications in the list of names. -;; RETURNS: an environment extending the given one, but in which each -;; name is bound to the corresponding value. -;; EXAMPLES: See tests below -;; STRATEGY: Use 2-argument map to map make-binding across names and -;; values, then append to prefix new bindings to env. -(define (make-env names values env) - (append - (map make-binding names values) - env)) - -;; env-lookup : Env Name -> Value -;; GIVEN: a representation of an environment env and a name n -;; RETURNS: the value of env(n), if it defined -;; EFFECT: raises "no binding" error if env(n) is undefined -;; STRATEGY: SD on Env -(define (env-lookup env n) - (cond - [(empty? env) (error 'env-lookup "no binding for ~s" n)] - [else - (if (equal? n (binding-name (first env))) - (binding-value (first env)) - (env-lookup (rest env) n))])) - - - -(begin-for-test - - ;; build the environment by hand. Note that shadowing is allowed by - ;; the data definition, even though make-env never builds an env - ;; with shadowing - (local - ((define env1 (list - (make-binding 'x 3) - (make-binding 'y 4) ; we say this binding for y - ; _shadows_ the one underneath. - (make-binding 'z 5) - (make-binding 'y 6) - (make-binding 'u 7)))) - (check-equal? (env-lookup env1 'x) 3) - (check-equal? (env-lookup env1 'y) 4) ; not 6 - (check-equal? (env-lookup env1 'z) 5) - (check-equal? (env-lookup env1 'u) 7) - (check-error (env-lookup env1 'v))) - - ;; now do it again using make-env - (local - ((define env1 - (make-env - (list 'x 'y 'z 'u) - (list 3 4 5 7) - empty-env))) - (check-equal? (env-lookup env1 'x) 3) - (check-equal? (env-lookup env1 'y) 4) - (check-equal? (env-lookup env1 'z) 5) - (check-equal? (env-lookup env1 'u) 7) - (check-error (env-lookup env1 'v))) - - ;; now do it again with make-env doing an extension - -(local - ((define env1 - (make-env - (list 'x 'y) - (list 3 4) - (make-env - (list 'y 'z 'u) - (list 8 5 7) - empty-env)))) - (check-equal? (env-lookup env1 'x) 3) - (check-equal? (env-lookup env1 'y) 4) ; not 8 - (check-equal? (env-lookup env1 'z) 5) - (check-equal? (env-lookup env1 'u) 7) - (check-error (env-lookup env1 'v))) - -) - - - diff --git a/Examples/12-interp/extras.rkt b/Examples/12-interp/extras.rkt deleted file mode 100644 index bcfe89b..0000000 --- a/Examples/12-interp/extras.rkt +++ /dev/null @@ -1,141 +0,0 @@ -#lang racket ; was #lang racket/base -(require (for-syntax racket/base) - racket/path - rackunit - rackunit/log) -(provide begin-for-test) -(provide provide rename-out struct-out check-error) -(provide check-location) - -(define extras-version "Wed Oct 15 13:09:22 2014") - -(printf "extras.rkt ~a~n" extras-version) - -(define-syntax (check-error stx) - (syntax-case stx () - [(_ code . msg) #`(check-exn exn:fail? (lambda () code) . msg)])) - - - -;; tests : (Parameterof (Listof (-> Void))) -;; Testing thunks in reverse order. -(define tests (make-parameter null)) - -(begin-for-syntax - ;; lifted-run-expr? : Boolean (mutable) - ;; True iff we've already appended a (run-all-tests) expr to the end - ;; of the current module. - (define lifted-run-expr? #f)) - -;; (begin-test expr ...) : module-level form -(define-syntax (begin-for-test stx) - (syntax-case stx () - [(_ expr ...) - (case (syntax-local-context) - [(module) - ;; In module (eg, defns buffer), add (run-all-tests) expr to end - ;; of module, unless previously added. - (unless lifted-run-expr? - (syntax-local-lift-module-end-declaration - #`(run-all-tests (quote #,(syntax-source stx)))) - (set! lifted-run-expr? #t)) - #'(tests (cons (lambda () (#%expression expr) ... (void)) (tests)))] - [(top-level) - ;; At top level (eg, interactions buffer), just run tests immediately. - ;; Alternative: disallow, like next case (but need different phrasing) - #'(begin (#%expression expr) ...)] - [else - (raise-syntax-error #f - "found a use of `begin-test' that is not at the top level" - stx)])])) - -;; run-all-tests : Any -> Void -;; Runs thunks in (tests) and clears (tests). -(define (run-all-tests src) - (define filename (path->string - (find-relative-path (current-directory) src - #:more-than-root? #t))) - (define ts (reverse (tests))) - (define msg - (cond [(path? src) - (format "Running tests from ~a...~n" - filename)] - [else "Running tests...~n"])) - (tests null) - (display msg) - (define start-failed+total (test-log)) - (define start-failed (car start-failed+total)) - (define start-total (cdr start-failed+total)) - (for ([t (in-list ts)]) (t)) - (define end-failed+total (test-log)) - (define failed (- (car end-failed+total) start-failed)) - (define total (- (cdr end-failed+total) start-total)) - (define (n-tests n) (format "~s ~a" n (if (= n 1) "test" "tests"))) - (cond [(zero? total) - (printf "There were no tests.\n")] - [(zero? failed) - (printf "All tests passed (~a).\n" (n-tests total))] - [else - (printf "~a failed out of ~a total in ~a.\n" - (n-tests failed) - (n-tests total) - filename)])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; check-location : String String -> Void -;; GIVEN: a 2 digit problem set number NN and the name of the file -;; being qualified. -;; EFFECT: throws an error if this file is not a directory of the form -;; pdp-*./setNN -(define (check-location NN correct-file-name) - (define path-elements (explode-path (current-directory))) - (define path-len (length path-elements)) - (define correct-folder-name (string-append "set" NN)) - (cond - [(>= path-len 2) - (define set-folder (path->string (last path-elements))) - (define pdp-folder (path->string (list-ref path-elements (- path-len 2)))) - (define set-regexp (regexp correct-folder-name)) - (define pdp-regexp (regexp "pdp-.*")) - (match* ((regexp-match? set-regexp set-folder) - (regexp-match? pdp-regexp pdp-folder)) - [(_ #f) - (error - (format - "File is in folder \"~a/~a\", which does not appear to be a local repo" - pdp-folder set-folder))] - [(#f _) - (error - (format - "File should be in a folder named ~a, but is in a folder named ~a" - correct-folder-name - set-folder))] - [(#t #t) - (printf - "~a appears to be in a correctly named folder. Running tests...~n" - correct-file-name)] - [(_ _) (void)])] - [else - (error - (format - "File should be in a folder named pdp-*/~a" - correct-folder-name))])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; for Problem Set 6, render-expr problem - -;; ListOf -> Void -;; GIVEN: A List of Strings -;; EFFECT: displays the strings in separate lines -;; RETURNS: the empty string -(define (display-strings! strs) - (if (empty? strs) (void) - (let* ((d1 (display (first strs))) - (d2 (display "\n"))) - (display-strings! (rest strs))))) - -(provide display-strings!) - - diff --git a/Examples/12-interp/interp-scratch.rkt b/Examples/12-interp/interp-scratch.rkt deleted file mode 100644 index 62abdef..0000000 --- a/Examples/12-interp/interp-scratch.rkt +++ /dev/null @@ -1,70 +0,0 @@ -#lang racket - -(require "datatypes.rkt") -(require "environments.rkt") - -(provide pgm-value) ;; Program -> Value - -;; Program -> Value -;; RETURNS: the value of the program -(define (pgm-value pgm) - (expr-value - (program-main pgm) - (decls2env (program-decls pgm)))) - -;; Expr Env -> Value -;; RETURNS: the value of the given expression in the given environment -(define (expr-value exp env) - (cond - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Utility Functions. -;;; These are here because they know about declarations. - -;; decls2env : Decls -> Env -(define (decls2env decls) - (make-env - (map decl-name decls) - (map decl-value decls) - empty-env)) - - -;; My cheat sheet: - - -;; Expr Env -> Value -;; RETURNS: the value of the given expression in the given environment -#;(define (expr-value exp env) - (cond - [(const? exp) (const-value exp)] - [(variable? exp) (env-lookup env (variable-name exp))] - [(diff? exp) (- (expr-value (diff-expr1 exp) env) - (expr-value (diff-expr2 exp) env))] - [(ifzero? exp) - (if (zero? (expr-value (ifzero-test exp) env)) - (expr-value (ifzero-then exp) env) - (expr-value (ifzero-else exp) env))] - [(call? exp) - (local - ((define the-fcn (env-lookup env (call-name exp))) - (define the-args - (map - (lambda (arg-expr) (expr-value arg-expr env)) - (call-exprs exp)))) - (expr-value - (fcn-decl-body the-fcn) - (make-env - (fcn-decl-args the-fcn) - the-args - env)))])) ; this is the _dynamic_ environment-- which is - ; wrong in general. Most languages, including - ; Racket, use a _static_ environment. Dealing - ; with the static environment isn't hard, but - ; requires more than 1 hr to develop. - - diff --git a/Examples/12-interp/interp.rkt b/Examples/12-interp/interp.rkt deleted file mode 100644 index 6ed1703..0000000 --- a/Examples/12-interp/interp.rkt +++ /dev/null @@ -1,63 +0,0 @@ -#lang racket - -(require "datatypes.rkt") -(require "environments.rkt") - -(provide pgm-value) ;; Program -> Value - -;; Program -> Value -;; RETURNS: the value of the program -(define (pgm-value pgm) - (expr-value - (program-main pgm) - (decls2env (program-decls pgm)))) - -;; Expr Env -> Value -;; RETURNS: the value of the given expression in the given environment -(define (expr-value exp env) - (cond - [(const? exp) (const-value exp)] - [(variable? exp) (env-lookup env (variable-name exp))] - [(diff? exp) (- (expr-value (diff-expr1 exp) env) - (expr-value (diff-expr2 exp) env))] - [(ifzero? exp) - (if (zero? (expr-value (ifzero-test exp) env)) - (expr-value (ifzero-then exp) env) - (expr-value (ifzero-else exp) env))] - [(call? exp) - (local - ((define the-fcn (env-lookup env (call-name exp))) - (define the-args - (map - (lambda (arg-expr) (expr-value arg-expr env)) - (call-exprs exp)))) - (expr-value - (fcn-decl-body the-fcn) - (make-env - (fcn-decl-args the-fcn) - the-args - env)))])) ; this is the _dynamic_ environment-- which is - ; wrong in general. Most languages, including - ; Racket, use a _static_ environment. Dealing - ; with the static environment isn't hard, but - ; requires more than 1 hr to develop. - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Utility Functions. -;;; These are here because they know about declarations. - -;; decls2env : Decls -> Env -(define (decls2env decls) - (make-env - (map decl-name decls) - (map decl-value decls) - empty-env)) - - - - - diff --git a/Examples/12-interp/tests.rkt b/Examples/12-interp/tests.rkt deleted file mode 100644 index 8897f8c..0000000 --- a/Examples/12-interp/tests.rkt +++ /dev/null @@ -1,251 +0,0 @@ -#lang racket - -(require "datatypes.rkt") -(require "interp.rkt") ; choose one of: interp.rkt, - ; interp-tuesday.rkt, or interp-wednesday.rkt -(require rackunit) -(require "extras.rkt") - -(begin-for-test - - ;; constants - - ;; 3 => 3 - - (check-equal? - (pgm-value - (make-program empty (make-const 3))) - 3) - - ;; difference expressions - - ;; (21 - 3) => 18 - - (check-equal? - (pgm-value - (make-program empty - (make-diff (make-const 21) (make-const 3)))) - 18) - - (check-equal? - (pgm-value - (make-program empty - (make-diff - (make-const 20) - (make-diff - (make-const 6) - (make-const 4))))) - 18) ;; 20 - (6 - 4) = 20 - 2 = 18 - - ;; (27 - 7) - (6 - 4) => 20 - 2 = 18 - (check-equal? - (pgm-value - (make-program empty - (make-diff - (make-diff (make-const 27) (make-const 7)) - (make-diff - (make-const 6) - (make-const 4))))) - 18) - - ;; if-expressions. - - (check-equal? - (pgm-value - (make-program empty - (make-ifzero - (make-diff (make-const 6) (make-const 4)) - (make-diff (make-const 20) (make-const 1)) - (make-diff (make-const 20) (make-const 3))))) - 17) - - (check-equal? - (pgm-value - (make-program empty - (make-ifzero - (make-diff (make-const 6) (make-const 6)) - (make-diff (make-const 20) (make-const 1)) - (make-diff (make-const 20) (make-const 3))))) - 19) - - ;; variables - - (check-equal? - (pgm-value - (make-program - (list - (make-const-decl 'x 14) - (make-const-decl 'y 4)) - (make-variable 'x))) - 14) - - (check-equal? - (pgm-value - (make-program - (list - (make-const-decl 'x 14) - (make-const-decl 'y 4)) - (make-variable 'y))) - 4) - - (check-equal? - (pgm-value - (make-program - (list - (make-const-decl 'x 14) - (make-const-decl 'y 4)) - (make-diff - (make-variable 'x) - (make-variable 'y)))) - 10) - - - - ;; single functions - - (check-equal? - (pgm-value - (make-program - (list - (make-const-decl 'x 14) - (make-const-decl 'y 4) - (make-fcn-decl 'f '(x) (make-diff - (make-variable 'x) - (make-const 3))) - (make-fcn-decl 'g '(x y) (make-diff - (make-variable 'x) - (make-variable 'y)))) - (make-call 'f (list (make-const 10))))) - 7) - - ;; fcn with two arguments - - (check-equal? - (pgm-value - (make-program - (list - (make-const-decl 'x 14) - (make-const-decl 'y 4) - (make-fcn-decl 'f '(x) (make-diff - (make-variable 'x) - (make-const 3))) - (make-fcn-decl 'g '(x y) (make-diff - (make-variable 'x) - (make-variable 'y)))) - (make-call 'g (list - (make-const 10) - (make-const 3))))) - 7) - - - - ;; one function calls another - - (check-equal? - (pgm-value - (make-program - (list - (make-const-decl 'x 14) - (make-const-decl 'y 4) - (make-fcn-decl 'f '(x) (make-diff - (make-variable 'x) - (make-const 3))) - (make-fcn-decl 'g '(x y) (make-diff - (make-variable 'x) - (make-variable 'y))) - (make-fcn-decl 'h '(u v) - (make-call 'f - (list (make-call 'g - (list - (make-variable 'u) - (make-variable 'v))))))) - (make-call 'h (list - (make-const 10) - (make-const 3))))) - 4) - - ;; (h 10 3) = (f (g 10 3)) = (f 7) = 4 - - - - ;; let's build a recursive function: prod. - - ;; First let's do sum: - - (check-equal? - (pgm-value - (make-program - (list - (make-fcn-decl 'sum '(a b) - (make-diff - (make-variable 'a) - (make-diff - (make-const 0) - (make-variable 'b))))) - (make-call - 'sum - (list - (make-const 5) - (make-const 11))))) - 16) - - ;; now we can do prod: - - (check-equal? - (pgm-value - (make-program - (list - (make-fcn-decl 'sum '(a b) - (make-diff - (make-variable 'a) - (make-diff - (make-const 0) - (make-variable 'b)))) - (make-fcn-decl 'prod '(x y) - (make-ifzero - (make-variable 'x) - (make-const 0) - (make-call - 'sum - (list - (make-variable 'y) - (make-call 'prod - (list - (make-diff - (make-variable 'x) - (make-const 1)) - (make-variable 'y)))))))) - (make-call 'prod - (list - (make-const 3) - (make-const 4))))) - 12) - - ;; example to demonstrate dynamic scoping - - (check-equal? - (pgm-value - (make-program - (list - (make-const-decl 'x 33) - (make-fcn-decl 'f '(x) - (make-call - 'g - (list (make-variable 'x)))) - (make-fcn-decl 'g '(y) - (make-variable 'x))) - ;; which x do we get? Under the usual static scoping, we'd - ;; expect the 33, but this interpreter gives us 44 - (make-call - 'f - (list - (make-const 44))))) - 44) - - - ) - - - - - diff --git a/Examples/Experimental/01-1-f2c.rkt b/Examples/Experimental/01-1-f2c.rkt deleted file mode 100644 index 6372ed4..0000000 --- a/Examples/Experimental/01-1-f2c.rkt +++ /dev/null @@ -1,59 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 01-1-f2c) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) -;; f2c.rkt : Simple Example showing the elements of the design recipe - -;; Goal: convert Fahrenheit to Celsius - -(require rackunit) -(require "extras.rkt") - -;; DATA DEFINITIONS: - -;; A FarenTemp is represented as a Real. -;; A CelsiusTemp is represented as a Real. - -;; f2c: FarenTemp -> CelsiusTemp -;; GIVEN: a temperature in Fahrenheit, -;; RETURNS: the equivalent temperature in Celsius. -;; EXAMPLES: -;; (f2c 32) = 0 -;; (f2c 212) = 100 -;; DESIGN STRATEGY: Transcribe Formula - -(define (f2c x) - (+ (* 5/9 x) -160/9)) - -;; TESTS -(begin-for-test - (check-equal? (f2c 32) 0 - "32 Fahrenheit should be 0 Celsius") - (check-equal? (f2c 212) 100 - "212 Fahrenheit should be 100 Celsius")) - -;; f2mars ; FarenTemp -> CelsiusTemp -;; GIVEN: A temperature in Fahrenheit -;; RETURNS: The mean temperature on the surface of Mars, in Celsius -;; EXAMPLE: -;; (f2mars ) = -451 -;; DESIGN STRATEGY: Return the constant answer -;; NOTE: I haven't looked this up, so I don't know if this is actually -;; the temperature on the surface of Mars. - -(define (f2mars x) - -451) - -;; TESTS: -;; 1. Look up the actual temperature on the surface of mars. -;; Insert it into the "..."s below. -;; 2. Run the test -(begin-for-test - (check-equal? (f2mars 0) ...) - (check-equal? (f2mars 100) ...)) - -;; Note: if you don't fill in the blanks, you will get a message like -;; ...: expected a finished expression, but found a template - -;; Note: -451 is almost certainly the wrong answer. Don't just fill in -451. - - diff --git a/Examples/Experimental/01-2-template-examples.c b/Examples/Experimental/01-2-template-examples.c deleted file mode 100644 index f864edd..0000000 --- a/Examples/Experimental/01-2-template-examples.c +++ /dev/null @@ -1,124 +0,0 @@ -/* This file should be an executable C program */ - -#include -#include - -/* In C, definitions must precede uses :( */ - -/* **************************************************************** */ - -/* ;; A Size is represented as one of the following integers: */ -/* ;; -- 8, 12, 16, 20, 30 */ -/* ;; INTERP: the size of the cup, in fluid ounces */ - -typedef enum {small = 8, med = 12, large = 16, venti = 20, trenti = 30} Size; - -/* NOTE: passing some other number for a Size will not raise an error :P */ - -/* **************************************************************** */ - -/* ;; A CoffeeType is represented as a string (any string will do) */ - -/* We typically work with a _pointer_ to a CoffeeType, - so we write CoffeeType* */ - -typedef char CoffeeType; - -typedef char String; -typedef String Foo; - -/* CONSTRUCTOR TEMPLATE */ - -/* CoffeeType* t = "..."; */ - -/* **************************************************************** */ - -/* ;; A MilkType is one of */ -/* ;; -- "black" */ -/* ;; -- "skim" */ -/* ;; -- "whole" */ -/* ;; -- "soy" */ - -typedef enum {black, skim, whole, soy} MilkType; - -/* CONSTRUCTOR PATTERN */ - -/* MilkType x = black; (or skim or whole or soy) */ - -/* OBSERVER PATTERN */ - -/* MilkTypeFunction : MilkType -> Sometype */ -/* */ -/* Sometype MilkTypeFunction (MilkType mt) { */ -/* switch (mt) { */ -/* case black : ... ; break; */ -/* case skim : ... ; break; */ -/* case whole : ... ; break; */ -/* case soy : ... ; break; */ -/* }} */ - - -/* **************************************************************** */ - -/* A CoffeeOrder is represented as a struct containing the - following fields: */ -/* INTERP: */ -/* size : Size is the size of cup desired */ -/* type : CoffeeType* is the kind of coffee order */ -/* milk : MilkType is the kind of milk ordered */ - -/* We typically work with a _pointer_ to a CoffeeOrder, so we write CoffeeOrder* */ - -typedef struct CoffeeOrder_ { - Size size; - CoffeeType* type; - MilkType milk; } CoffeeOrder; - - -/* CONSTRUCTOR TEMPLATE */ - -CoffeeOrder* make_coffeeorder (Size size, - CoffeeType* type, - MilkType milk) -{ - CoffeeOrder* o = malloc(sizeof(struct CoffeeOrder*)); - o->size = size; - o->type = type; - o->milk = milk; - return o; -} - -/* OBSERVER TEMPLATE */ - -/* CoffeeOrderFn : CoffeeOrder* -> SomeType */ - -/* SomeType CoffeeOrderFn (CoffeeOrder* o) */ -/* { ... o->size ... o->type ... o->milk; */ -/* return ...; */ -/* } */ - -/* **************************************************************** */ - -/* TESTS */ - -char* milktype2string (MilkType mt) { - switch (mt) { - case black : return ("black"); - case skim : return ("skim"); - case whole : return ("whole"); - case soy : return ("soy"); - }} - -void main() -{ - CoffeeType* c = "French Roast"; - printf("%s\n", c); - /* make a coffee order */ - CoffeeOrder* o = make_coffeeorder(small, c, soy); - printf("%d\n", o->size); - printf("%s\n", milktype2string(o->milk)); - printf("\nGoodbye Cruel World"); - - -} - diff --git a/Examples/Experimental/01-2-template-examples.rkt b/Examples/Experimental/01-2-template-examples.rkt deleted file mode 100644 index a663c50..0000000 --- a/Examples/Experimental/01-2-template-examples.rkt +++ /dev/null @@ -1,219 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 01-2-template-examples) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) -(require rackunit) -(require "extras.rkt") - - -;;; New-Style Data Definitions - -;; In the new style, a Data Definition is a link between a piece of -;; information (something in the real world), and a piece of data -;; (something in the computer). - -;; To emphasize this, we add the words "is represented as" in every -;; data definition. - -;; In the new style, we will abandon both constructor templates and -;; observer templates. Instead we will concentrate on a picture of -;; the data, as it might appear in the repl. - -;; For structs, we put the field names in the representation and the -;; types in the interpretations. - -;; We prefer that the types of the fields be given in terms of the -;; information they represent, rather than in terms of how that -;; information is represented. However, this is a flexible criterion. - -;; In the examples below, sections labeled "NOTE" are intended as -;; commentary, and not as something a student would be asked to write. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A CoffeeOrder is represented as (coffee-order size type milk?) -;; with the following fields: -;; INTERP: -;; size : Size is the size of cup desired -;; type : CoffeeType is the kind of coffee order -;; milk : MilkType is the kind of milk ordered - -(define-struct coffee-order (size type milk)) - -;; NOTE: As per Will's advice, we'll have constructor and observer -;; templates as deliverables, but we can drop them later on when -;; everybody gets it. - -;; CONSTRUCTOR TEMPLATE - -;; (make-coffee-order Size CoffeeType MilkType) - -;; OBSERVER TEMPLATE - -;; coffee-order-fn : CoffeeOrder -> ?? -#; -(define (coffee-order-fn co) - (... - (coffee-order-size co) - (coffee-order-type co) - (coffee-order-milk co))) - - -;; NOTE: (coffee-order ...) in the first line is NOT a constructor. -;; It is a picture of the data as it might be printed out. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A Size is represented as one of the following integers: -;; -- 8, 12, 16, 20, 30 -;; INTERP: the size of the cup, in fluid ounces - -;; NOTE: Constructor template is not necessary for itemization data - -;; OBSERVER TEMPLATE: - -;; size-fn : Size -> ? -#; -(define (size-fn s) - (cond - [(= s 8) ...] - [(= s 12) ...] - [(= s 16) ...] - [(= s 20) ...] - [(= s 30) ...])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A CoffeeType is represented as a string (any string will do) - -;; NOTE: In a more detailed representation, we might specify this further. - -;; NOTE: Any time you write String, you MUST write "any string will -;; do". This should eliminate definitions of the form "A Direction -;; is a String". Possible similarly for Number (?). - -;; A MilkType is one of -;; -- "black" -;; -- "skim" -;; -- "whole" -;; -- "soy" - -;; CONSTRUCTOR TEMPLATE: Not needed for an itemization type - -;; OBSERVER TEMPLATE: - -;; milk-fn : MilkType -> ? -#; -(define (milk-fn m) - (cond - [(string=? m "black") ...] - [(string=? m "skim") ...] - [(string=? m "whole") ...] - [(string=? m "soy") ...])) - -;; NOTE: we don't need interpretations for CoffeeType or MilkType -;; because we believe the reader can figure this out. If we were -;; doing this in some other language, or if we believe the reader -;; would not understand these terms well enough to write the code, -;; then we would have to have a more elaborate interpretation. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A WineOrder is represented as (wine-order vineyard vintage) -;; with the following fields: -;; INTERP: -;; vineyard : Vineyard the origin of the grapes -;; vintage : Vintage the vintage of the grapes - -;; A Vineyard is represented as a String (any string will do) -;; A Vintage is represented as a positive integer in [1800,2100] - -;; NOTE: it would be OK to write either or both of the following: - -;; vineyard : the origin of the grapes, represented as a string (any -;; string will do) -;; vintage : PosInt[1800,2100] the vintage of the grapes - -(define-struct wine-order (vineyard vintage)) - -;; CONSTRUCTOR TEMPLATE: (make-wine-order Vineyard Vintage) - -;; OBSERVER TEMPLATE: - -;; wine-order-fn : WineOrder -> ?? -#; -(define (wine-order-fn wo) - (... - (wine-order-vineyard wo) - (wine-order-vintage wo))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A TeaOrder is represented as (tea-order size type) -;; INTERP: -;; size : Size the size of cup desired -;; type : TeaType the type of tea to be used - -(define-struct tea-order (size type)) - -;; A TeaType is represented as a String (any string will do) - -;; NOTE: similarly, it would be OK to write -;; type : String the type of tea to be used, represented as a string -;; (any string will do) -;; It would NOT be OK to write -;; size : NonNegInt the size of the cup desired, in fluid ounces -;; because the size is supposed to be one of the 5 possibilities -;; above. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A BarOrder is one of -;; -- a CoffeeOrder -;; -- a WineOrder -;; -- a TeaOrder - -;; bo-fn : BarOrder -> ?? -;; STRATEGY: Cases on order : BarOrder -(define (bo-fn order) - (cond - [(coffee-order? order) ...] - [(wine-order? order) ...] - [(tea-order? order) ...])) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Another example: - -(define-struct book (author title on-hand price)) - -;; A Book is represented as a (book-record title on-hand price) -;; INTERP: -;; title : Title is the title of the book -;; author : Author is the author of the book -;; on-hand : NonNegInt is the number of copies on hand -;; price : Price is the price of the book - -;; A Price is a NonNegInt -;; INTERP: a price in USD*100 -;; EXAMPLE: 795 represents the price $7.95 - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Example template for itemization data - -;; A Size is one of -;; -- "small" -;; -- "medium" -;; -- "large" - -;; size-fn : Size -> ?? -(define (size-fn s) - (cond - [(string=? s "small") ...] - [(string=? s "medium") ...] - [(string=? s "large") ...])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - diff --git a/Examples/Experimental/01-2A-vinyard-example.c b/Examples/Experimental/01-2A-vinyard-example.c deleted file mode 100644 index ef9d3dd..0000000 --- a/Examples/Experimental/01-2A-vinyard-example.c +++ /dev/null @@ -1,112 +0,0 @@ -/* This file should be an executable C program */ - -/* This will be the type definition for WineOrder, TeaOrder, and - BarOrder (= WineOrder | TeaOrder) */ - -#include -#include - -typedef char String; - -/* ;; A Vineyard is represented as a String (any string will do) */ - -typedef String Vineyard; - -/* CONSTRUCTOR TEMPLATE */ - -/* Vineyard* y = "..."; */ - -/* ;; A Vintage is represented as a positive integer in [1800,2100] */ - -typedef int Vintage; - -/* ********************************************* */ - -/* A WineOrder is represented as a struct containing the following - fields: - - vineyard : Vineyard the origin of the grapes - vintage : Vintage the vintage of the grape - - */ - -typedef struct { - Vineyard* vineyard; - Vintage vintage; -} WineOrder; - -/* CONSTRUCTOR FUNCTION */ - -WineOrder* make_wineorder (Vineyard* v, - Vintage y) -{ - WineOrder* w = malloc(sizeof(struct WineOrder*)); - w->vineyard = v; - w->vintage = y; - return w; -} - -/* **************************************************************** */ - -/* A TeaType is represented as a string (any string will do) */ -typedef String TeaType; - -/* A Size is represented as a non-negative integer */ -typedef int Size; -/* non-negativeness is not checked */ - -/* A TeaOrder is a represented as a structure containing the following - fields: - - size : Size -- the size of cup desired, in ounces - type : TeaType -- the type of to be used - - */ - -typedef struct { - Size size; - TeaType* type; -} *TeaOrder; - -/* CONSTRUCTOR FUNCTION */ -TeaOrder make_teaorder (Size s, - TeaType* t) -{ - TeaOrder o = malloc(sizeof(struct TeaOrder*)); - o->size = s; - o->type = t; - return o; -} - -/* A BarOrder is one of - -- a WineOrder - -- a TeaOrder - */ - -/* A BarOrder is represented as a tagged union */ - -typedef struct { - enum {W, O} type; - union { - WineOrder* wineorder; - TeaOrder* teaorder; - } data; -} *BarOrder; - -void tester (BarOrder bo) { - switch (bo->type) { }; -} - - - -void main () -{ - WineOrder* o = make_wineorder ("Chateau Lafitte", 1993); - printf("vineyard = %s year = %s\n",o->vineyard,o->vintage); - printf("Goodbye, Cruel World."); -} - - - - - diff --git a/Examples/Experimental/01-2C.c b/Examples/Experimental/01-2C.c deleted file mode 100644 index 92c215b..0000000 --- a/Examples/Experimental/01-2C.c +++ /dev/null @@ -1,146 +0,0 @@ -/* This file should be an executable C program */ - -#include -#include - -/* A String is represented as a pointer to a null-terminated array of - characters. */ - -typedef char *String; - -typedef enum - {small = 8, med = 12, large = 16, venti = 20, trenti = 30} - CoffeeSize; - -typedef String CoffeeType; - -/* CONSTRUCTOR TEMPLATE */ - -CoffeeType t = "Sumatra"; - -typedef enum {black, skim, whole, soy} MilkType; - -MilkType x = black; - -/* OBSERVER PATTERN */ - -/* MilkTypeFunction : MilkType -> Sometype */ -/* */ -/* Sometype MilkTypeFunction (MilkType mt) { */ -/* switch (mt) { */ -/* case black : ... ; break; */ -/* case skim : ... ; break; */ -/* case whole : ... ; break; */ -/* case soy : ... ; break; */ -/* }} */ - - -/* **************************************************************** */ - -/* A CoffeeOrder is represented as a pointer to a struct containing the - following fields: */ -/* INTERP: */ -/* size : Size is the size of cup desired */ -/* type : CoffeeType* is the kind of coffee order */ -/* milk : MilkType is the kind of milk ordered */ - -typedef struct CoffeeOrder_ { - CoffeeSize size; - CoffeeType type; - MilkType milk; } * CoffeeOrder; - - -/* CONSTRUCTOR FUNCTION */ - -CoffeeOrder make_coffeeorder (CoffeeSize size, - CoffeeType type, - MilkType milk) -{ - CoffeeOrder o = malloc(sizeof(struct CoffeeOrder_)); - o->size = size; - o->type = type; - o->milk = milk; - return o; -} - -/* OBSERVER TEMPLATE */ - -/* CoffeeOrderFn : CoffeeOrder* -> SomeType */ - -/* SomeType CoffeeOrderFn (CoffeeOrder* o) */ -/* { ... o->size ... o->type ... o->milk; */ -/* return ...; */ -/* } */ - -/* **************************************************************** */ - -/* A TeaType is represented as a string (any string will do) */ -typedef String TeaType; - -/* A Size is represented as a non-negative integer */ -typedef int Size; -/* non-negativeness is not checked */ - -/* A TeaOrder is a represented as a structure containing the following - fields: - - size : Size -- the size of cup desired, in ounces - type : TeaType -- the type of to be used - - */ - -typedef struct TeaOrder_ { - Size size; - TeaType type; -} *TeaOrder; - -/* CONSTRUCTOR FUNCTION */ -TeaOrder make_teaorder (Size s, - TeaType t) -{ - TeaOrder o = malloc(sizeof(struct TeaOrder_)); - o->size = s; - o->type = t; - return o; -} - -typedef struct { - enum {order_coffee, order_tea} order_type; - union { - TeaOrder* teaorder; - CoffeeOrder_ coffeeorder; - } data; -} * Order ; - - -void tester (Order o) { - switch (o->order_type) { - case order_coffee : printf("%s\n", o->data.coffeeorder.type); - case order_tea : ; - } -} - - -/* TESTS */ - -char* milktype2string (MilkType mt) { - switch (mt) { - case black : return ("black"); - case skim : return ("skim"); - case whole : return ("whole"); - case soy : return ("soy"); - }} - -void main() -{ - CoffeeType c = "French Roast"; - printf("%s\n", c); - /* make a coffee order */ - CoffeeOrder o = make_coffeeorder(small, c, soy); - printf("%d\n", o->size); - printf("%s\n", milktype2string(o->milk)); - printf("\nGoodbye Cruel World"); - - -} - diff --git a/Examples/Experimental/01-coffee.c b/Examples/Experimental/01-coffee.c deleted file mode 100644 index 5d0b2fe..0000000 --- a/Examples/Experimental/01-coffee.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Examples of Data Definition style, in C */ -/* This file should be an executable C program */ - -#include -#include - -/* In C, declarations must precede uses :( */ - -/* In C, we will generally represent data other than numerics as - POINTERS to the underlying data */ - -/* SCALAR DATA */ - -/* A FarenTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Farenheit */ - -/* A CelsiusTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Celsius */ - -typedef double faren_temp; -typedef double celsius_temp; - -/* f2c: FarenTemp -> CelsiusTemp */ -/* GIVEN: a temperature in Fahrenheit, */ -/* RETURNS: the equivalent temperature in Celsius. */ - -celsius_temp f2c (faren_temp f); /* { ... } */ - - -/* strings */ -/* A string is represented by a pointer to an array of characters */ -typedef char * String; - -/* **************************************************************** */ - -/* A CoffeeType is represented as a string (any string will do) */ -typedef String CoffeeType; - -/* A Size is a cup size, in ounces */ -typedef int Size; - - -/* **************************************************************** */ - -/* A CoffeeOrder is represented as a pointer to a struct containing - * the following fields: - * INTERP: - * size : Size the size of the cup being ordered - * kind : CoffeeType the kind of coffee being ordered -*/ - -typedef struct CoffeeOrder_ { - Size size; - CoffeeType kind; - } * CoffeeOrder; - -/* CONSTRUCTOR TEMPLATE */ - -CoffeeOrder make_coffeeorder (Size size, - CoffeeType kind) -{ - CoffeeOrder o = malloc(sizeof(o)); - o->size = size; - o->kind = kind; - return o; -} - -/* An OrderList is a pointer to a singly-linked list of coffee orders. */ - -typedef struct OrderList_ { - CoffeeOrder first ; - struct OrderList_ * rest; -} * OrderList; - -OrderList emptylist = NULL; - -OrderList cons (CoffeeOrder o, OrderList ol) -{ - OrderList lst = malloc(sizeof(lst)); - lst->first = o; - lst->rest = ol; - return lst; -} - -int total_size (OrderList lst) -{ - if (lst == NULL) - {return 0;} - else - { - int firstsize = lst->first->size; - int totalrest = total_size(lst->rest); - return (firstsize + totalrest); - } -} - -int main() -{ - CoffeeType c = "French Roast"; - printf("c = %s\n", c); - CoffeeOrder o1 = make_coffeeorder(101, c); - printf("The first size is: %d\n", o1->size); - - CoffeeType c2 = "Decaf"; - CoffeeOrder o2 = make_coffeeorder(201,c2); - - CoffeeOrder o3 = make_coffeeorder(301, "Dunkin Decaf"); - - OrderList lst = cons (o3, cons (o2, cons(o1, emptylist))); - printf("Total of sizes = %d\n", total_size(lst)); - - printf("\nGoodbye Cruel World\n"); - return 1; -} - - - - - - diff --git a/Examples/Experimental/01-data-definitions - Copy.c b/Examples/Experimental/01-data-definitions - Copy.c deleted file mode 100644 index 71109bb..0000000 --- a/Examples/Experimental/01-data-definitions - Copy.c +++ /dev/null @@ -1,397 +0,0 @@ -/* Examples of Data Definition style, in C */ -/* This file should be an executable C program */ - -#include -#include - -/* In C, definitions must precede uses :( */ - -/* In C, we will generally represent data other than numerics as - POINTERS to the underlying data */ - - - -/* SCALAR DATA */ - -/* A FarenTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Farenheit */ - -/* A CelsiusTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Celsius */ - -typedef double faren_temp; -typedef double celsius_temp; - -/* f2c: FarenTemp -> CelsiusTemp */ -/* GIVEN: a temperature in Fahrenheit, */ -/* RETURNS: the equivalent temperature in Celsius. */ - -/* celsius_temp f2c (faren_temp f) { ... } */ - - -/* strings */ -typedef char String; - -/* **************************************************************** */ - -/* ;; A Size is represented as one of the following integers: */ -/* ;; -- 8, 12, 16, 20, 30 */ -/* ;; INTERP: the size of the cup, in fluid ounces */ - -typedef enum {small = 8, med = 12, large = 16, venti = 20, trenti = 30} Size; - -/* NOTE: passing some other number for a Size will not raise an error :P */ - -/* **************************************************************** */ - -/* A CoffeeType is represented as a string (any string will do) */ - -typedef String CoffeeType; - -/* **************************************************************** */ - -/* A MilkType is one of */ -/* -- black */ -/* -- skim */ -/* -- whole */ -/* -- soy */ - -typedef enum {black, skim, whole, soy} MilkType; - -/* CONSTRUCTOR PATTERN */ - -/* MilkType x = black; (or skim or whole or soy) */ - -/* OBSERVER PATTERN */ - -/* MilkTypeFunction : MilkType -> Sometype */ -/* */ -/* Sometype MilkTypeFunction (MilkType mt) { */ -/* switch (mt) { */ -/* case black : ...; return (...) ; */ -/* case skim : ...; return (...) ; */ -/* case whole : ...; return (...) ; */ -/* case soy : ...; return (...) ; */ -/* }} */ - -/* **************************************************************** */ - -/* A CoffeeOrder is represented as a struct containing the - following fields: */ -/* INTERP: */ -/* size : Size is the size of cup desired */ -/* type : CoffeeType* is the kind of coffee order */ -/* milk : MilkType is the kind of milk ordered */ - -/* We typically work with a _pointer_ to a CoffeeOrder, so we write - CoffeeOrder* -*/ - -typedef struct { - Size size; - CoffeeType* type; - MilkType milk; } CoffeeOrder; - -/* CONSTRUCTOR TEMPLATE */ - -CoffeeOrder* make_coffeeorder (Size size, - CoffeeType* type, - MilkType milk) -{ - CoffeeOrder* o = malloc(sizeof(struct CoffeeOrder*)); - o->size = size; - o->type = type; - o->milk = milk; - return o; -} - -/* OBSERVER TEMPLATE */ - -/* CoffeeOrderFn : CoffeeOrder* -> SomeType */ - -/* SomeType CoffeeOrderFn (CoffeeOrder* o) */ -/* { sz = o->size; */ -/* ty = o->type; */ -/* m = o->milk; */ -/* ...; */ -/* return (...): */ -/* } */ - -/* **************************************************************** */ -/* WineOrder and its associated types */ - - -/* ;; A Vineyard is represented as a String (any string will do) */ - -typedef String Vineyard; - -/* CONSTRUCTOR TEMPLATE */ - -/* Vineyard* y = "..."; */ - -/* ;; A Vintage is represented as a positive integer in [1800,2100] */ - -typedef int Vintage; - -/* ********************************************* */ - -/* A WineOrder is represented as a struct containing the following - fields: - - vineyard : Vineyard the origin of the grapes - vintage : Vintage the vintage of the grape - - */ - -typedef struct { - Vineyard* vineyard; - Vintage vintage; -} WineOrder; - -/* CONSTRUCTOR FUNCTION */ - -WineOrder* make_wineorder (Vineyard* v, - Vintage y) -{ - WineOrder* w = malloc(sizeof(struct WineOrder*)); - w->vineyard = v; - w->vintage = y; - return w; -} - -/* OBSERVER TEMPLATE */ - -/* WineOrderFn : WineOrder* -> SomeType */ - -/* -SomeType WineOrderFn (WineOrder* o) -{ v = o->vineyard; - y = o->vintage; - ...; - return ...; -} -*/ - -/* A TeaOrder is represented as a struct containing the following - fields: - - size : Size the size of cup desired - type : TeaType* the type of tea to be used - - */ - -typedef String TeaType; /* any string will do */ - -typedef struct { - Size size; - TeaType* type; } TeaOrder; - -/* constructor function */ - -TeaOrder* make_TeaOrder (Size s, - TeaType* t) -{ - TeaOrder* o = malloc(sizeof(struct TeaOrder*)); - o->size = s; - o->type = t; - return o; -} - - -/* A BarOrder is one of */ -/* -- a CoffeeOrder */ -/* -- a WineOrder */ -/* -- a TeaOrder */ - -/* An itemization type that is a union of non-scalars is represented - as a tagged union */ - -typedef struct { - enum {CO_, WO_, TO_} order_type; - union data_ { - CoffeeOrder* coffee_order; - WineOrder* wine_order; - TeaOrder* tea_order; - } data; -} BarOrder; - - - -/* constructors */ - -BarOrder* make_coffee_barorder (Size size, - CoffeeType* type, - MilkType milk) -{ - BarOrder* o = malloc(sizeof(struct BarOrder*)); - o->order_type = CO_; - o->data.coffee_order = make_coffeeorder(size, type, milk); - return o; -} - -/* etc. */ - -/* Observer Template */ - -/* SomeBarOrderFn : BarOrder* -> SomeType */ -/* -SomeType Some BarOrderFn (BarOrder* o) -{ - switch (o->order_type) { - case CO_ : - { - CoffeeOrder* co = o->data.coffee_order; - Size sz = co->size; - CoffeeType* ty = co->type; - MilkType m = co->milk; - ...; - return ...; - } - case WO_ : ...etc... - case TO_ : ...etc... - } -}; -*/ - -/* EXAMPLE: - - Here I've omitted unnecessary components. Note that for tea - orders, I could have written - - return o->data.tea_order->size; - - But long strings of accessors like that are difficult to write - correctly and to read. Definitely not beautiful! - - */ - -/* BarOrder* -> Size */ -/* Returns the size of the given bar order. Assumes all wine orders - are size 'venti' :) */ - -Size BarOrder_size (BarOrder* o) -{ - switch (o->order_type) { - case CO_ : - { - CoffeeOrder* co = o->data.coffee_order; - return (co->size); - } - case WO_ : - { return(venti); } - - case TO_ : - { - TeaOrder* to = o->data.tea_order; - return (to->size); - /* return o->data.tea_order->size; */ - } - } -}; - -/* **************************************************************** */ - -/* Lists */ - -/* An ISBN is represented as an int */ - -typedef int ISBN; - -/* rather than having a struct for a BookStatus and another struct - for a list of BookStatus, we will write idiomatic C, in which - these are combined.*/ - - -/* An Inventory is represented as a struct containing the following - fields: - - title : Title* the title of the first book in the inventory - isbn : ISBN the isbn of the first book in the inventory - num_on_hand : int the number of copies of this book on hand - next : *Inventory a pointer to the rest of the inventory, if any. - - */ - -typedef String Title; - -typedef struct inventory_ { - Title* title; - ISBN isbn; - int num_on_hand; - struct inventory_ * next; -} Inventory; - -/* constructors */ - -Inventory* empty_inventory = NULL; - -Inventory* cons_inventory (Title* t, ISBN isbn, int n, Inventory* inv) -{ - Inventory* o = malloc(sizeof(Inventory*)); - o->title = t; - o->isbn = isbn; - o->num_on_hand = n; - o->next = inv; - return o; -} - -/* observer template */ - -/* SomeFunction : Inventory* -> SomeType */ - -/* -Sometype SomeInvFunction (Inventory* inv) -{ - if (inv == NULL) - {return ...;} - else - { - String t = inv->title; - ISBN i = inv->isbn; - int on_hand = inv->num_on_hand; - Inventory* rest = inv->next; - return ...; - } -} -*/ - - -/* example: */ -/* total_copies : Inventory* -> int */ -/* RETURNS: the total number of books on hand */ -int total_copies (Inventory* inv) -{ - if (inv == NULL) - {return 0;} - else - { - int on_hand = inv->num_on_hand; - Inventory* rest = inv->next; - return (on_hand + total_copies(rest)); - } -} - - -void main() -{ - CoffeeType* c = "French Roast"; - printf("%s\n", c); - /* make a coffee order at the bar */ - CoffeeOrder* o = make_coffeeorder(small, c, soy); - printf("The size is: %d\n", o->size); - - Inventory* i1 = cons_inventory("The Brothers Karamzov", 12345, 101, - empty_inventory); - Inventory* i2 = cons_inventory("War and Peace", 678910, 201, i1); - - printf("Total books = %d\n", total_copies(i2)); - - - printf("\nGoodbye Cruel World"); -} - - - - - - diff --git a/Examples/Experimental/01-data-definitions-in-c.txt b/Examples/Experimental/01-data-definitions-in-c.txt deleted file mode 100644 index 71109bb..0000000 --- a/Examples/Experimental/01-data-definitions-in-c.txt +++ /dev/null @@ -1,397 +0,0 @@ -/* Examples of Data Definition style, in C */ -/* This file should be an executable C program */ - -#include -#include - -/* In C, definitions must precede uses :( */ - -/* In C, we will generally represent data other than numerics as - POINTERS to the underlying data */ - - - -/* SCALAR DATA */ - -/* A FarenTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Farenheit */ - -/* A CelsiusTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Celsius */ - -typedef double faren_temp; -typedef double celsius_temp; - -/* f2c: FarenTemp -> CelsiusTemp */ -/* GIVEN: a temperature in Fahrenheit, */ -/* RETURNS: the equivalent temperature in Celsius. */ - -/* celsius_temp f2c (faren_temp f) { ... } */ - - -/* strings */ -typedef char String; - -/* **************************************************************** */ - -/* ;; A Size is represented as one of the following integers: */ -/* ;; -- 8, 12, 16, 20, 30 */ -/* ;; INTERP: the size of the cup, in fluid ounces */ - -typedef enum {small = 8, med = 12, large = 16, venti = 20, trenti = 30} Size; - -/* NOTE: passing some other number for a Size will not raise an error :P */ - -/* **************************************************************** */ - -/* A CoffeeType is represented as a string (any string will do) */ - -typedef String CoffeeType; - -/* **************************************************************** */ - -/* A MilkType is one of */ -/* -- black */ -/* -- skim */ -/* -- whole */ -/* -- soy */ - -typedef enum {black, skim, whole, soy} MilkType; - -/* CONSTRUCTOR PATTERN */ - -/* MilkType x = black; (or skim or whole or soy) */ - -/* OBSERVER PATTERN */ - -/* MilkTypeFunction : MilkType -> Sometype */ -/* */ -/* Sometype MilkTypeFunction (MilkType mt) { */ -/* switch (mt) { */ -/* case black : ...; return (...) ; */ -/* case skim : ...; return (...) ; */ -/* case whole : ...; return (...) ; */ -/* case soy : ...; return (...) ; */ -/* }} */ - -/* **************************************************************** */ - -/* A CoffeeOrder is represented as a struct containing the - following fields: */ -/* INTERP: */ -/* size : Size is the size of cup desired */ -/* type : CoffeeType* is the kind of coffee order */ -/* milk : MilkType is the kind of milk ordered */ - -/* We typically work with a _pointer_ to a CoffeeOrder, so we write - CoffeeOrder* -*/ - -typedef struct { - Size size; - CoffeeType* type; - MilkType milk; } CoffeeOrder; - -/* CONSTRUCTOR TEMPLATE */ - -CoffeeOrder* make_coffeeorder (Size size, - CoffeeType* type, - MilkType milk) -{ - CoffeeOrder* o = malloc(sizeof(struct CoffeeOrder*)); - o->size = size; - o->type = type; - o->milk = milk; - return o; -} - -/* OBSERVER TEMPLATE */ - -/* CoffeeOrderFn : CoffeeOrder* -> SomeType */ - -/* SomeType CoffeeOrderFn (CoffeeOrder* o) */ -/* { sz = o->size; */ -/* ty = o->type; */ -/* m = o->milk; */ -/* ...; */ -/* return (...): */ -/* } */ - -/* **************************************************************** */ -/* WineOrder and its associated types */ - - -/* ;; A Vineyard is represented as a String (any string will do) */ - -typedef String Vineyard; - -/* CONSTRUCTOR TEMPLATE */ - -/* Vineyard* y = "..."; */ - -/* ;; A Vintage is represented as a positive integer in [1800,2100] */ - -typedef int Vintage; - -/* ********************************************* */ - -/* A WineOrder is represented as a struct containing the following - fields: - - vineyard : Vineyard the origin of the grapes - vintage : Vintage the vintage of the grape - - */ - -typedef struct { - Vineyard* vineyard; - Vintage vintage; -} WineOrder; - -/* CONSTRUCTOR FUNCTION */ - -WineOrder* make_wineorder (Vineyard* v, - Vintage y) -{ - WineOrder* w = malloc(sizeof(struct WineOrder*)); - w->vineyard = v; - w->vintage = y; - return w; -} - -/* OBSERVER TEMPLATE */ - -/* WineOrderFn : WineOrder* -> SomeType */ - -/* -SomeType WineOrderFn (WineOrder* o) -{ v = o->vineyard; - y = o->vintage; - ...; - return ...; -} -*/ - -/* A TeaOrder is represented as a struct containing the following - fields: - - size : Size the size of cup desired - type : TeaType* the type of tea to be used - - */ - -typedef String TeaType; /* any string will do */ - -typedef struct { - Size size; - TeaType* type; } TeaOrder; - -/* constructor function */ - -TeaOrder* make_TeaOrder (Size s, - TeaType* t) -{ - TeaOrder* o = malloc(sizeof(struct TeaOrder*)); - o->size = s; - o->type = t; - return o; -} - - -/* A BarOrder is one of */ -/* -- a CoffeeOrder */ -/* -- a WineOrder */ -/* -- a TeaOrder */ - -/* An itemization type that is a union of non-scalars is represented - as a tagged union */ - -typedef struct { - enum {CO_, WO_, TO_} order_type; - union data_ { - CoffeeOrder* coffee_order; - WineOrder* wine_order; - TeaOrder* tea_order; - } data; -} BarOrder; - - - -/* constructors */ - -BarOrder* make_coffee_barorder (Size size, - CoffeeType* type, - MilkType milk) -{ - BarOrder* o = malloc(sizeof(struct BarOrder*)); - o->order_type = CO_; - o->data.coffee_order = make_coffeeorder(size, type, milk); - return o; -} - -/* etc. */ - -/* Observer Template */ - -/* SomeBarOrderFn : BarOrder* -> SomeType */ -/* -SomeType Some BarOrderFn (BarOrder* o) -{ - switch (o->order_type) { - case CO_ : - { - CoffeeOrder* co = o->data.coffee_order; - Size sz = co->size; - CoffeeType* ty = co->type; - MilkType m = co->milk; - ...; - return ...; - } - case WO_ : ...etc... - case TO_ : ...etc... - } -}; -*/ - -/* EXAMPLE: - - Here I've omitted unnecessary components. Note that for tea - orders, I could have written - - return o->data.tea_order->size; - - But long strings of accessors like that are difficult to write - correctly and to read. Definitely not beautiful! - - */ - -/* BarOrder* -> Size */ -/* Returns the size of the given bar order. Assumes all wine orders - are size 'venti' :) */ - -Size BarOrder_size (BarOrder* o) -{ - switch (o->order_type) { - case CO_ : - { - CoffeeOrder* co = o->data.coffee_order; - return (co->size); - } - case WO_ : - { return(venti); } - - case TO_ : - { - TeaOrder* to = o->data.tea_order; - return (to->size); - /* return o->data.tea_order->size; */ - } - } -}; - -/* **************************************************************** */ - -/* Lists */ - -/* An ISBN is represented as an int */ - -typedef int ISBN; - -/* rather than having a struct for a BookStatus and another struct - for a list of BookStatus, we will write idiomatic C, in which - these are combined.*/ - - -/* An Inventory is represented as a struct containing the following - fields: - - title : Title* the title of the first book in the inventory - isbn : ISBN the isbn of the first book in the inventory - num_on_hand : int the number of copies of this book on hand - next : *Inventory a pointer to the rest of the inventory, if any. - - */ - -typedef String Title; - -typedef struct inventory_ { - Title* title; - ISBN isbn; - int num_on_hand; - struct inventory_ * next; -} Inventory; - -/* constructors */ - -Inventory* empty_inventory = NULL; - -Inventory* cons_inventory (Title* t, ISBN isbn, int n, Inventory* inv) -{ - Inventory* o = malloc(sizeof(Inventory*)); - o->title = t; - o->isbn = isbn; - o->num_on_hand = n; - o->next = inv; - return o; -} - -/* observer template */ - -/* SomeFunction : Inventory* -> SomeType */ - -/* -Sometype SomeInvFunction (Inventory* inv) -{ - if (inv == NULL) - {return ...;} - else - { - String t = inv->title; - ISBN i = inv->isbn; - int on_hand = inv->num_on_hand; - Inventory* rest = inv->next; - return ...; - } -} -*/ - - -/* example: */ -/* total_copies : Inventory* -> int */ -/* RETURNS: the total number of books on hand */ -int total_copies (Inventory* inv) -{ - if (inv == NULL) - {return 0;} - else - { - int on_hand = inv->num_on_hand; - Inventory* rest = inv->next; - return (on_hand + total_copies(rest)); - } -} - - -void main() -{ - CoffeeType* c = "French Roast"; - printf("%s\n", c); - /* make a coffee order at the bar */ - CoffeeOrder* o = make_coffeeorder(small, c, soy); - printf("The size is: %d\n", o->size); - - Inventory* i1 = cons_inventory("The Brothers Karamzov", 12345, 101, - empty_inventory); - Inventory* i2 = cons_inventory("War and Peace", 678910, 201, i1); - - printf("Total books = %d\n", total_copies(i2)); - - - printf("\nGoodbye Cruel World"); -} - - - - - - diff --git a/Examples/Experimental/01-data-definitions.c b/Examples/Experimental/01-data-definitions.c deleted file mode 100644 index 71109bb..0000000 --- a/Examples/Experimental/01-data-definitions.c +++ /dev/null @@ -1,397 +0,0 @@ -/* Examples of Data Definition style, in C */ -/* This file should be an executable C program */ - -#include -#include - -/* In C, definitions must precede uses :( */ - -/* In C, we will generally represent data other than numerics as - POINTERS to the underlying data */ - - - -/* SCALAR DATA */ - -/* A FarenTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Farenheit */ - -/* A CelsiusTemp is represented as a Real */ -/* Interp: r represents the temperature r degrees Celsius */ - -typedef double faren_temp; -typedef double celsius_temp; - -/* f2c: FarenTemp -> CelsiusTemp */ -/* GIVEN: a temperature in Fahrenheit, */ -/* RETURNS: the equivalent temperature in Celsius. */ - -/* celsius_temp f2c (faren_temp f) { ... } */ - - -/* strings */ -typedef char String; - -/* **************************************************************** */ - -/* ;; A Size is represented as one of the following integers: */ -/* ;; -- 8, 12, 16, 20, 30 */ -/* ;; INTERP: the size of the cup, in fluid ounces */ - -typedef enum {small = 8, med = 12, large = 16, venti = 20, trenti = 30} Size; - -/* NOTE: passing some other number for a Size will not raise an error :P */ - -/* **************************************************************** */ - -/* A CoffeeType is represented as a string (any string will do) */ - -typedef String CoffeeType; - -/* **************************************************************** */ - -/* A MilkType is one of */ -/* -- black */ -/* -- skim */ -/* -- whole */ -/* -- soy */ - -typedef enum {black, skim, whole, soy} MilkType; - -/* CONSTRUCTOR PATTERN */ - -/* MilkType x = black; (or skim or whole or soy) */ - -/* OBSERVER PATTERN */ - -/* MilkTypeFunction : MilkType -> Sometype */ -/* */ -/* Sometype MilkTypeFunction (MilkType mt) { */ -/* switch (mt) { */ -/* case black : ...; return (...) ; */ -/* case skim : ...; return (...) ; */ -/* case whole : ...; return (...) ; */ -/* case soy : ...; return (...) ; */ -/* }} */ - -/* **************************************************************** */ - -/* A CoffeeOrder is represented as a struct containing the - following fields: */ -/* INTERP: */ -/* size : Size is the size of cup desired */ -/* type : CoffeeType* is the kind of coffee order */ -/* milk : MilkType is the kind of milk ordered */ - -/* We typically work with a _pointer_ to a CoffeeOrder, so we write - CoffeeOrder* -*/ - -typedef struct { - Size size; - CoffeeType* type; - MilkType milk; } CoffeeOrder; - -/* CONSTRUCTOR TEMPLATE */ - -CoffeeOrder* make_coffeeorder (Size size, - CoffeeType* type, - MilkType milk) -{ - CoffeeOrder* o = malloc(sizeof(struct CoffeeOrder*)); - o->size = size; - o->type = type; - o->milk = milk; - return o; -} - -/* OBSERVER TEMPLATE */ - -/* CoffeeOrderFn : CoffeeOrder* -> SomeType */ - -/* SomeType CoffeeOrderFn (CoffeeOrder* o) */ -/* { sz = o->size; */ -/* ty = o->type; */ -/* m = o->milk; */ -/* ...; */ -/* return (...): */ -/* } */ - -/* **************************************************************** */ -/* WineOrder and its associated types */ - - -/* ;; A Vineyard is represented as a String (any string will do) */ - -typedef String Vineyard; - -/* CONSTRUCTOR TEMPLATE */ - -/* Vineyard* y = "..."; */ - -/* ;; A Vintage is represented as a positive integer in [1800,2100] */ - -typedef int Vintage; - -/* ********************************************* */ - -/* A WineOrder is represented as a struct containing the following - fields: - - vineyard : Vineyard the origin of the grapes - vintage : Vintage the vintage of the grape - - */ - -typedef struct { - Vineyard* vineyard; - Vintage vintage; -} WineOrder; - -/* CONSTRUCTOR FUNCTION */ - -WineOrder* make_wineorder (Vineyard* v, - Vintage y) -{ - WineOrder* w = malloc(sizeof(struct WineOrder*)); - w->vineyard = v; - w->vintage = y; - return w; -} - -/* OBSERVER TEMPLATE */ - -/* WineOrderFn : WineOrder* -> SomeType */ - -/* -SomeType WineOrderFn (WineOrder* o) -{ v = o->vineyard; - y = o->vintage; - ...; - return ...; -} -*/ - -/* A TeaOrder is represented as a struct containing the following - fields: - - size : Size the size of cup desired - type : TeaType* the type of tea to be used - - */ - -typedef String TeaType; /* any string will do */ - -typedef struct { - Size size; - TeaType* type; } TeaOrder; - -/* constructor function */ - -TeaOrder* make_TeaOrder (Size s, - TeaType* t) -{ - TeaOrder* o = malloc(sizeof(struct TeaOrder*)); - o->size = s; - o->type = t; - return o; -} - - -/* A BarOrder is one of */ -/* -- a CoffeeOrder */ -/* -- a WineOrder */ -/* -- a TeaOrder */ - -/* An itemization type that is a union of non-scalars is represented - as a tagged union */ - -typedef struct { - enum {CO_, WO_, TO_} order_type; - union data_ { - CoffeeOrder* coffee_order; - WineOrder* wine_order; - TeaOrder* tea_order; - } data; -} BarOrder; - - - -/* constructors */ - -BarOrder* make_coffee_barorder (Size size, - CoffeeType* type, - MilkType milk) -{ - BarOrder* o = malloc(sizeof(struct BarOrder*)); - o->order_type = CO_; - o->data.coffee_order = make_coffeeorder(size, type, milk); - return o; -} - -/* etc. */ - -/* Observer Template */ - -/* SomeBarOrderFn : BarOrder* -> SomeType */ -/* -SomeType Some BarOrderFn (BarOrder* o) -{ - switch (o->order_type) { - case CO_ : - { - CoffeeOrder* co = o->data.coffee_order; - Size sz = co->size; - CoffeeType* ty = co->type; - MilkType m = co->milk; - ...; - return ...; - } - case WO_ : ...etc... - case TO_ : ...etc... - } -}; -*/ - -/* EXAMPLE: - - Here I've omitted unnecessary components. Note that for tea - orders, I could have written - - return o->data.tea_order->size; - - But long strings of accessors like that are difficult to write - correctly and to read. Definitely not beautiful! - - */ - -/* BarOrder* -> Size */ -/* Returns the size of the given bar order. Assumes all wine orders - are size 'venti' :) */ - -Size BarOrder_size (BarOrder* o) -{ - switch (o->order_type) { - case CO_ : - { - CoffeeOrder* co = o->data.coffee_order; - return (co->size); - } - case WO_ : - { return(venti); } - - case TO_ : - { - TeaOrder* to = o->data.tea_order; - return (to->size); - /* return o->data.tea_order->size; */ - } - } -}; - -/* **************************************************************** */ - -/* Lists */ - -/* An ISBN is represented as an int */ - -typedef int ISBN; - -/* rather than having a struct for a BookStatus and another struct - for a list of BookStatus, we will write idiomatic C, in which - these are combined.*/ - - -/* An Inventory is represented as a struct containing the following - fields: - - title : Title* the title of the first book in the inventory - isbn : ISBN the isbn of the first book in the inventory - num_on_hand : int the number of copies of this book on hand - next : *Inventory a pointer to the rest of the inventory, if any. - - */ - -typedef String Title; - -typedef struct inventory_ { - Title* title; - ISBN isbn; - int num_on_hand; - struct inventory_ * next; -} Inventory; - -/* constructors */ - -Inventory* empty_inventory = NULL; - -Inventory* cons_inventory (Title* t, ISBN isbn, int n, Inventory* inv) -{ - Inventory* o = malloc(sizeof(Inventory*)); - o->title = t; - o->isbn = isbn; - o->num_on_hand = n; - o->next = inv; - return o; -} - -/* observer template */ - -/* SomeFunction : Inventory* -> SomeType */ - -/* -Sometype SomeInvFunction (Inventory* inv) -{ - if (inv == NULL) - {return ...;} - else - { - String t = inv->title; - ISBN i = inv->isbn; - int on_hand = inv->num_on_hand; - Inventory* rest = inv->next; - return ...; - } -} -*/ - - -/* example: */ -/* total_copies : Inventory* -> int */ -/* RETURNS: the total number of books on hand */ -int total_copies (Inventory* inv) -{ - if (inv == NULL) - {return 0;} - else - { - int on_hand = inv->num_on_hand; - Inventory* rest = inv->next; - return (on_hand + total_copies(rest)); - } -} - - -void main() -{ - CoffeeType* c = "French Roast"; - printf("%s\n", c); - /* make a coffee order at the bar */ - CoffeeOrder* o = make_coffeeorder(small, c, soy); - printf("The size is: %d\n", o->size); - - Inventory* i1 = cons_inventory("The Brothers Karamzov", 12345, 101, - empty_inventory); - Inventory* i2 = cons_inventory("War and Peace", 678910, 201, i1); - - printf("Total books = %d\n", total_copies(i2)); - - - printf("\nGoodbye Cruel World"); -} - - - - - - diff --git a/Examples/Experimental/01-data-definitions.java b/Examples/Experimental/01-data-definitions.java deleted file mode 100644 index acb70c8..0000000 --- a/Examples/Experimental/01-data-definitions.java +++ /dev/null @@ -1,160 +0,0 @@ -// Examples of Data Definition style, in Java - -// This file should be an executable Java program - -// In Java, most data is internally represented by pointers, as it is -// in Racket. - -// In Java, there are no functions, only methods that live in a class. -// The class contains its own constructor method. -// The methods of the class are observers; there may be several -// observers for the same class. - - - -// SCALAR DATA - -// Scalar Data, and Itemizations of Scalar Data, can be implemented as -// scalar values. - -// Examples: - -// A FarenTemp is represented as a Real -// Interp: r represents the temperature r degrees Farenheit - -// A CelsiusTemp is represented as a Real -// Interp: r represents the temperature r degrees Celsius - -// A Size is represented as an int -// WHERE: the size is one of -// -- 8, 12, 16, 20, 30 -// INTERP: the size of the cup, in fluid ounces - - -// A CoffeeType is represented as a String (any string will do) - -// A TeaType is represented as a String (any string will do) - -// ********************************************************************** - -// Itemizations of Scalar Data - -// These can also be implemented as scalar values - -// A MilkType is represented as a String, which must be one of the -// following: -// -- "black" -// -- "skim" -// -- "whole" -// -- "soy" - -// CONSTRUCTOR TEMPLATE: not necessary - -// OBSERVER EXAMPLE: - -class MilkExample { - static int to_int (String s) - { switch (s) { - case "black" : return 1; - case "skim" : return 2; - case "whole" : return 3; - case "soy" : return 4; - default : throw new RunTimeException("illegal MilkType"); - } - } -} - - - -// Information types vs. Data types: - -// Java does not have typedefs, so you can't say -// typedef double faren_temp, -// as we did in the C-language examples. - -// So we must rely on our contracts to tell us the information that is -// associated with the data :( - -class TempExample { - - // f2c : FarenTemp -> CelsiusTemp - // GIVEN: a temperature in Fahrenheit, - // RETURNS: the equivalent temperature in Celsius. - public static double f2c (double f) { - return ( (5/9) * f - (160 / 9)) ; - } - -} - -// Compound Data - -// In Java, compound data is generally represented as a class. -// Instead of a constructor template, we have a constructor -// method. - - - - -// ;; A CoffeeOrder is represented as an object of class CoffeeOrderObj -// ;; with the following fields: -// ;; INTERP: -// ;; size : Size is the size of cup desired -// ;; type : CoffeeType is the kind of coffee order -// ;; milk : MilkType is the kind of milk ordered - -class CoffeeOrderObj { - int size; -} - - - -class WineOrder { - String vineyard; - String vintage ; - WineOrder (String vy, String vn) { - vineyard = vy; - vintage = vn; - } - // no methods yet -} - -// TeaOrders: - -// A TeaType is represented as a String - -// A TeaOrder is represented as an object of class TeaOrderObj with -// interface: - -// TeaOrder (Size s, TeaType ty) -// Size to_size () -// String to_type () - -// class TeaOrderObj { -// Size size; -// String type; -// TeaOrderObj () {}; -// } - - -class DataDefs { - - public static void main (String[] args) { - SizeObj sz = new SizeObj(20); - System.out.printf("%s\n",sz.to_String()); - System.out.println("Goodbye, cruel world!"); - } -} - - - - - - - - - - - - - - diff --git a/Examples/Experimental/01-data-definitions.txt b/Examples/Experimental/01-data-definitions.txt deleted file mode 100644 index 2046c5b..0000000 --- a/Examples/Experimental/01-data-definitions.txt +++ /dev/null @@ -1,232 +0,0 @@ -New-Style Data Definitions - -In the new style, a Data Definition is a link between a piece of -information (something in the real world), and a piece of data -(something in the computer). - -To emphasize this, we add the words "is represented as" in every -data definition. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -DATA DEFINITIONS FOR SCALAR DATA - -;; A FarenTemp is represented as a Real -;; Interp: r represents the temperature r degrees Farenheit - -;; A CelsiusTemp is represented as a Real -;; Interp: r represents the temperature r degrees Celsius - -;; f2c: FarenTemp -> CelsiusTemp -;; GIVEN: a temperature in Fahrenheit, -;; RETURNS: the equivalent temperature in Celsius. -;; EXAMPLES: -;; (f2c 32) = 0 -;; (f2c 212) = 100 -;; DESIGN STRATEGY: Transcribe Formula - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -DATA DEFINITIONS FOR COMPOUND DATA - -For structs, we put the field names in the representation and the -types in the interpretations. - -We prefer that the types of the fields be given in terms of the -information they represent, rather than in terms of how that -information is represented. However, this is a flexible criterion. - -In the examples below, sections labeled "NOTE" are intended as -commentary, and not as something a student would be asked to write. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A CoffeeOrder is represented as (coffee-order size type milk?) -;; with the following fields: -;; INTERP: -;; size : Size is the size of cup desired -;; type : CoffeeType is the kind of coffee order -;; milk : MilkType is the kind of milk ordered - -(define-struct coffee-order (size type milk)) - -NOTE: Here (coffee-order ...) in the first line is NOT a constructor. -It is a picture of the data as it might be printed out. - -NOTE: As per Will's advice, we'll have constructor and observer -templates as deliverables, but we can drop them later on when -everybody gets it. - -;; CONSTRUCTOR TEMPLATE -;; (make-coffee-order Size CoffeeType MilkType) - -;; OBSERVER TEMPLATE -;; coffee-order-fn : CoffeeOrder -> ?? -#; -(define (coffee-order-fn co) - (... - (coffee-order-size co) - (coffee-order-type co) - (coffee-order-milk co))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A Size is represented as one of the following integers: -;; -- 8, 12, 16, 20, 30 -;; INTERP: the size of the cup, in fluid ounces - -NOTE: Constructor template is not necessary for itemization data - -;; OBSERVER TEMPLATE: - -;; size-fn : Size -> ? -#; -(define (size-fn s) - (cond - [(= s 8) ...] - [(= s 12) ...] - [(= s 16) ...] - [(= s 20) ...] - [(= s 30) ...])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A CoffeeType is represented as a string (any string will do) - -NOTE: Any time you write String, you MUST write "any string will -do". This should eliminate definitions of the form "A Direction -is a String". Possible similarly for Number (?). - -NOTE: In a more detailed representation, we might specify this further. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A MilkType is one of -;; -- "black" -;; -- "skim" -;; -- "whole" -;; -- "soy" - -;; CONSTRUCTOR TEMPLATE: Not needed for an itemization type in Racket -;; note: this may be needed Java or C. - -;; OBSERVER TEMPLATE: - -;; milk-fn : MilkType -> ? -#; -(define (milk-fn m) - (cond - [(string=? m "black") ...] - [(string=? m "skim") ...] - [(string=? m "whole") ...] - [(string=? m "soy") ...])) - -NOTE: we don't need interpretations for CoffeeType or MilkType -because we believe the reader can figure this out. If we were -doing this in some other language, or if we believe the reader -would not understand these terms well enough to write the code, -then we would have to have a more elaborate interpretation. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A WineOrder is represented as (wine-order vineyard vintage) -;; with the following fields: -;; INTERP: -;; vineyard : Vineyard the origin of the grapes -;; vintage : Vintage the vintage of the grapes - -;; A Vineyard is represented as a String (any string will do) -;; A Vintage is represented as a positive integer in [1800,2100] - -NOTE: it would be OK to write either or both of the following: - -;; vineyard : the origin of the grapes, represented as a string (any -;; string will do) -;; vintage : PosInt[1800,2100] the vintage of the grapes - -(define-struct wine-order (vineyard vintage)) - -;; CONSTRUCTOR TEMPLATE: (make-wine-order Vineyard Vintage) - -;; OBSERVER TEMPLATE: - -;; wine-order-fn : WineOrder -> ?? -#; -(define (wine-order-fn wo) - (... - (wine-order-vineyard wo) - (wine-order-vintage wo))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A TeaOrder is represented as (tea-order size type) -;; INTERP: -;; size : Size the size of cup desired -;; type : TeaType the type of tea to be used - -(define-struct tea-order (size type)) - -;; A TeaType is represented as a String (any string will do) - -;; NOTE: similarly, it would be OK to write -;; type : String the type of tea to be used, represented as a string -;; (any string will do) -;; It would NOT be OK to write -;; size : NonNegInt the size of the cup desired, in fluid ounces -;; because the size is supposed to be one of the 5 possibilities -;; above. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -In the new scheme, we no longer have mixed data as a category of -data. Instead, we will allow an itemization where the alternatives -are non-scalars: - -;; A BarOrder is one of -;; -- a CoffeeOrder -;; -- a WineOrder -;; -- a TeaOrder - -;; bo-fn : BarOrder -> ?? -;; STRATEGY: Cases on order : BarOrder -(define (bo-fn order) - (cond - [(coffee-order? order) ...] - [(wine-order? order) ...] - [(tea-order? order) ...])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -DATA DEFINITIONS FOR LIST DATA - -We will treat ListOf<..> as a primitive "representation constructor" - -;; An Inventory is represented as a ListOf, in increasing -;; ISBN order, with at most one entry per ISBN. - -Note that here we've put the constraints on order and multiplicity -right in the data definition. - -;; CONSTRUCTOR TEMPLATES - -;; empty -;; (cons bs inv) - -- WHERE - bs is a BookStatus - inv is an Inventory - and - (bookstatus-isbn bs) is less than the ISBN of any book in inv. - -;; OBSERVER TEMPLATE: - -;; inv-fn : Inventory -> ?? -#; -(define (inv-fn inv) - (cond - [(empty? inv) ...] - [else (... - (first inv) - (inv-fn (rest inv)))])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - diff --git a/Examples/Experimental/AST.c b/Examples/Experimental/AST.c deleted file mode 100644 index d08314f..0000000 --- a/Examples/Experimental/AST.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include - -typedef char *String; - -typedef enum - {small = 8, med = 12, large = 16, venti = 20, trenti = 30} - Size; - -/* - A Foo is one of - | a Bar, which is a string and a boolean - | a Baz, which is an int and a ListOf(Foo) - - */ - -typedef struct Foo_ { - enum {bar_foo, baz_foo} tag; - union { - struct {String name; bool flag;} bar; - struct { - int val; - struct Foo_ *next; - } baz; - } data; -} *Foo ; - -/* OR: */ - -/* Have a Baz contain a list of Foos: */ - -struct Foo2_ { - enum {bar_foo2, baz_foo2} tag; - union { - struct {String name; bool flag;} bar; - struct { - int val; - struct Foo_ next; - } baz; - } data; -}; -typedef struct Foo2_ Foo2; - - - -Foo make_bar(String name, bool flag) { - Foo f = malloc(sizeof(Foo*)); /* either Foo* or (struct Foo_) works here */ - f->tag = bar_foo; - f->data.bar.name = name; - f->data.bar.flag = flag; - return f; -} - -Foo make_baz (int v) { - Foo f = malloc(sizeof(struct Foo_)); - f->tag = baz_foo; - f->data.baz.val = v; - return f; -} - -void main () { - printf("GoodBye Cruel World") -} - - - - diff --git a/Examples/Experimental/AST2.c b/Examples/Experimental/AST2.c deleted file mode 100644 index fa41eec..0000000 --- a/Examples/Experimental/AST2.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -typedef char *String; - -typedef enum - {small = 8, med = 12, large = 16, venti = 20, trenti = 30} - Size; - -/* - A Foo is one of - | a Bar, which is a string and a boolean - | a Baz, which is an int - - */ - -typedef struct {String name; bool flag;} *Bar; - -typedef struct {int val;} *Baz; - -typedef struct Foo_ { - enum {bar, baz} tag; - union {Bar bar; Baz baz;} data; -} *Foo ; - -Bar make_bar(String name, bool flag) { - Bar o = malloc(sizeof(Bar*)); /* either Foo* or (struct Foo_) works here */ - o->name = name; - o->flag = flag; - return o; -} - -Baz make_baz(int v) { - Baz o = malloc(sizeof(Baz*)); - o->val = v; - return o; -} - -Foo Bar2Foo(Bar b) { - Foo f = malloc(sizeof(Foo*)); - f->tag = bar; - f->data.bar = bar; - return f; -} - - -void main () { -} - - - - diff --git a/Examples/Experimental/DataDefs.class b/Examples/Experimental/DataDefs.class deleted file mode 100644 index 8358774..0000000 Binary files a/Examples/Experimental/DataDefs.class and /dev/null differ diff --git a/Examples/Experimental/HelloWorld.class b/Examples/Experimental/HelloWorld.class deleted file mode 100644 index fe65d5b..0000000 Binary files a/Examples/Experimental/HelloWorld.class and /dev/null differ diff --git a/Examples/Experimental/Size.class b/Examples/Experimental/Size.class deleted file mode 100644 index 2755306..0000000 Binary files a/Examples/Experimental/Size.class and /dev/null differ diff --git a/Examples/Experimental/Size1.class b/Examples/Experimental/Size1.class deleted file mode 100644 index 526a8b1..0000000 Binary files a/Examples/Experimental/Size1.class and /dev/null differ diff --git a/Examples/Experimental/SizeObj.class b/Examples/Experimental/SizeObj.class deleted file mode 100644 index 47dc69e..0000000 Binary files a/Examples/Experimental/SizeObj.class and /dev/null differ diff --git a/Examples/Experimental/TempExample.class b/Examples/Experimental/TempExample.class deleted file mode 100644 index 4e61329..0000000 Binary files a/Examples/Experimental/TempExample.class and /dev/null differ diff --git a/Examples/Experimental/WineOrder.class b/Examples/Experimental/WineOrder.class deleted file mode 100644 index ffdf771..0000000 Binary files a/Examples/Experimental/WineOrder.class and /dev/null differ diff --git a/Examples/Experimental/a.exe b/Examples/Experimental/a.exe deleted file mode 100644 index e4958c9..0000000 Binary files a/Examples/Experimental/a.exe and /dev/null differ diff --git a/Examples/Experimental/peter.c b/Examples/Experimental/peter.c deleted file mode 100644 index d66f6c3..0000000 --- a/Examples/Experimental/peter.c +++ /dev/null @@ -1,28 +0,0 @@ -struct bar_order_ops { - int (*size)(struct bar_order*); - /* … */ -} -typedef struct bar_order { - struct bar_order_ops *ops; - /* public fields - total price? etc. */ - void *private; -} -static int coffee_order_size(struct bar_order* b) { - struct coffee_order *c = b->private; - return c->size; -} -static struct bar_order_ops coffee_ops = { - .size = coffee_order_size; - /* …. */ -} -struct bar_order *make_coffee_order(… arguments) { - struct bar_order *b = malloc(sizeof(*b)); - struct coffee_order *c = malloc(sizeof(*c)); - c->size = something; - b->ops = &coffee_ops; - b->private = c; - return c; -} -… -struct bar_order *b = make_coffee_order(…); -int size = b->ops.size(b); diff --git a/Examples/Old Module 05/05-1-find-dog.rkt b/Examples/Old Module 05/05-1-find-dog.rkt deleted file mode 100644 index 00dfb9c..0000000 --- a/Examples/Old Module 05/05-1-find-dog.rkt +++ /dev/null @@ -1,80 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname 05-1-find-dog) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) -(require rackunit) -(require "extras.rkt") - -;; An Animal is represented as a String (any string will do) -;; Here, by "Animal" we mean an animal species, not an individual animal. - -;; An AnimalSequence is represented as a list of Animal. - -;; CONSTRUCTOR TEMPLATE: -;; empty Interp: the empty sequence -;; (cons a as) -;; WHERE: -;; a is an Animal Interp: the first animal in the sequence -;; as is an AnimalSequence -;; Interp: the rest of the animals in the sequence - -;; OBSERVER TEMPLATE: -;; animal-seq-fn : AnimalSequence -> ?? -(define (animal-seq-fn as) - (cond - [(empty? as) ...] - [else (... (first as) - (animal-seq-fn (rest as)))])) - -;; find-dog : AnimalSequence -> Boolean -;; RETURNS: true if "dog" is in the given sequence -;; STRATEGY: Use observer template for AnimalSequence -#;(define (find-dog as) - (cond - [(empty? as) false] - [else (or - (string=? (first as) "dog") - (find-dog (rest as)))])) - -(begin-for-test - (check-equal? (find-dog (list "cat" "dog" "weasel")) true) - (check-equal? (find-dog (list "cat" "elephant" "weasel")) false)) - -;; find-cat : AnimalSequence -> Boolean -;; RETURNS: true if "cat" is in the given sequence -;; STRATEGY: Use observer template for AnimalSequence -#;(define (find-cat as) - (cond - [(empty? as) false] - [else (or - (string=? (first as) "cat") - (find-cat (rest as)))])) - -(begin-for-test - (check-equal? (find-cat (list "cat" "dog" "weasel")) true) - (check-equal? (find-cat (list "elephant" "weasel")) false)) - -;; find-animal : AnimalSequence Animal -> Boolean -;; GIVEN: A list of strings and a string -;; RETURNS: true iff the given Animal is in the given los. -;; STRATEGY: Use template for on as -(define (find-animal as a) - (cond - [(empty? as) false] - [else (or - (string=? (first as) a) - (find-animal (rest as) a))])) - -(begin-for-test - "find-animal" - (check-equal? (find-animal (list "cat" "elephant" "weasel") "elephant") - true) - (check-equal? (find-animal (list "cat" "elephant" "weasel") "beaver") - false)) - -;; STRATEGY: Call a more general function -(define (find-dog as) - (find-animal as "dog")) - -;; STRATEGY: Call a more general function -(define (find-cat as) - (find-animal as "cat")) diff --git a/Examples/Old Module 05/05-2-pizza.rkt b/Examples/Old Module 05/05-2-pizza.rkt deleted file mode 100644 index 3e3599c..0000000 --- a/Examples/Old Module 05/05-2-pizza.rkt +++ /dev/null @@ -1,39 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 05.1-replace-anchovies-with-onions) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -;; Data Definitions: - -;; A Topping is represented as a String (any string will do) - -;; A Pizza is represented as list of Topping, listed from top to bottom. - -;; pizza-fn : Pizza -> ?? -;; Given a Pizza, produce .... -;; (define (pizza-fn p) -;; (cond -;; [(empty? p) ...] -;; [else (... (first p) -;; (pizza-fn (rest p)))])) - -;; Examples: -(define plain-pizza empty) -(define cheese-pizza (list "cheese")) -(define anchovies-cheese-pizza (list "anchovies" "cheese")) - -;;; This is the original function definition, from the slides: - -;; replace-all-anchovies-with-onions -;; : Pizza -> Pizza -;; RETURNS: a pizza like the given pizza, but with -;; anchovies in place of each layer of onions -;; STRATEGY: Use observer template for Pizza on p -(define (replace-all-anchovies-with-onions p) - (cond - [(empty? p) empty] - [else (if (string=? (first p) "anchovies") - (cons "onions" - (replace-all-anchovies-with-onions - (rest p))) - (cons (first p) - (replace-all-anchovies-with-onions - (rest p))))])) diff --git a/Examples/Old Module 05/05-3-map.rkt b/Examples/Old Module 05/05-3-map.rkt deleted file mode 100644 index d2277a5..0000000 --- a/Examples/Old Module 05/05-3-map.rkt +++ /dev/null @@ -1,216 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-intermediate-reader.ss" "lang")((modname abstractions) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -;;; Examples of generalization - -;;; HtDP talks about "abstraction", but we prefer the term "generalization". - -(require rackunit) -(require "extras.rkt") - -;; Data -;; -- empty -;; -- (cons X ListOfX) - -;; TEMPLATE: -;; lox-fn : ListOfX -> ?? -;; (define (lox-fn lst) -;; (cond -;; [(empty? lst) ...] -;; [else (... -;; (first lst) -;; (lox-fn (rest lst)))])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; example 1: -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; ListOfNumber -> ListOfNumber -;; GIVEN: a list of numbers -;; RETURNS: the list obtained by adding 1 to each number -;; EXAMPLE: (10 20 30) => (11 21 31) -;; STRATEGY: Use template for ListOfNumber on lon -(define (add-1-to-each lon) - (cond - [(empty? lon) empty] - [else (cons (add1 (first lon)) - (add-1-to-each (rest lon)))])) - -(begin-for-test - (check-equal? - (add-1-to-each (list 22 33 44)) - (list 23 34 45))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Employee -(define-struct employee (name salary)) -;; interpretation omitted... - -;; A ListOfEmployee is either -;; -- empty -;; -- (cons Employee ListOfEmployee) - -;; TEMPLATE: -;; lox-fn : ListOfEmployee -> ?? -;; (define (loe-fn lst) -;; (cond -;; [(empty? lst) ...] -;; [else (... -;; (employee-fn (first lst)) -;; (loe-fn (rest lst)))])) - - - - -;; employee-names : ListOfEmployee -> ListOfString -;; GIVEN: a list of employees -;; RETURNS: the list of their names -;; STRATEGY: Use template for ListOfEmployee on loe -(define (employee-names loe) - (cond - [(empty? loe) empty] - [else (cons (employee-name (first loe)) - (employee-names (rest loe)))])) - -(define loe1 - (list (make-employee "Joe" 100) - (make-employee "Steve" 300))) - -(begin-for-test - (check-equal? (employee-names loe1) (list "Joe" "Steve"))) - -;; Generalize these to: - -;; apply-to-each : (X->Y) ListOfX -> ListOfY -;; GIVEN: a list lox and a function f -;; RETURNS: the list obtained by applying f to each element of lox -;; EXAMPLES: -;; (apply-to-each (list 10 20 30) add1) = (list 11 21 31) -;; (apply-to-each (list 1 2 3) sqr) = (list 1 4 9) -;; STRATEGY: Use template for ListOfX to lox -(define (apply-to-each fn lox) - (cond - [(empty? lox) empty] - [else (cons (fn (first lox)) - (apply-to-each fn (rest lox)))])) - -;; This is built into ISL under the name "map". That is the version -;; you should use in your own code. - -;; map : (X -> Y) ListOfX -> ListOfY - -;; versions using the generalization: - -;; comment out the old definitions and uncomment these to test. - -;; ;; STRATEGY: Use HOF apply-to-each to lon -;; (define (add-1-to-each lon) -;; (apply-to-each add1 lon)) - -;; ;; STRATEGY: Use HOF apply-to-each on loe -;; (define (employee-names loe) -;; (apply-to-each employee-name loe)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; More uses of apply-to-each -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; STRATEGY: Use HOF apply-to-each on lon -(define (add-5-to-each lon) - (local - ((define (add5 n) (+ n 5))) - (apply-to-each add5 lon))) - -;; Number ListOfNumber -> ListOfNumber -;; GIVEN: a number n and list of numbers lon -;; RETURNS: the list obtained by adding n to each element of the list -;; EXAMPLE: -;; (add-to-each 4 (list 20 30 40)) = (list 24 34 44) -;; STRATEGY: Apply HOF apply-to-each to lon. - -(define (add-to-each x lon) - (local - ((define (addx n) (+ n x))) - (apply-to-each addx lon))) - -(begin-for-test - (check-equal? - (add-to-each 4 (list 20 30 40)) - (list 24 34 44)) - (check-equal? - (add-5-to-each (list 20 30 40)) - (list 25 35 45))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Example 2: -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; sum : ListOfNumber -> Number -;; GIVEN: a list of numbers -;; RETURNS: their sum -;; STRATEGY: Use template for ListOfNumber on lon - -(define (sum lon) - (cond - [(empty? lon) 0] - [else (+ - (first lon) - (sum (rest lon)))])) - -;; product : ListOfNumber -> Number -;; GIVEN: a list of numbers -;; RETURNS: their product -;; STRATEGY: Use template for ListOfNumber on lon - -(define (product lon) - (cond - [(empty? lon) 1] - [else (* - (first lon) - (product (rest lon)))])) - -(begin-for-test - (check-equal? (sum (list 2 3 4)) 9) - (check-equal? (product (list 2 3 4)) 24)) - -;;; Generalized function: - -;; my-foldr: (Number Number -> Number) Number ListOfNumber -> Number -;; STRATEGY: Use template for ListOfNumber on lon -(define (my-foldr combiner base lon) - (cond - [(empty? lon) base] - [else (combiner - (first lon) - (my-foldr combiner base (rest lon)))])) - -;; This is built in to ISL under the name "foldr". That is the version -;; you should use in your own code. -;; The most general contract for foldr is -;; foldr : (X Y -> Y) Y ListOfX -> Y - -;; now we can define sum and product in terms of my-foldr - -;; ;; STRATEGY: Use HOF my-foldr on lon -;; (define (sum lon) -;; (my-foldr + 0 lon)) - -;; ;; STRATEGY: Use HOF my-foldr on lon -;; (define (product lon) -;; (my-foldr * 1 lon)) - -;; Be sure to test these. - -;;; Can define apply-to-each in terms of my-foldr: - -;; ;; STRATEGY: Use HOF my-foldr on lox -;; (define (apply-to-each lox fn) -;; (local -;; ((define (combiner first-guy result-on-the-rest) -;; (cons (fn first-guy) -;; result-on-the-rest))) -;; (my-foldr combiner empty lox))) - -;; Try using this definition of apply-to-each in place of the -;; definition above. diff --git a/Examples/Old Module 05/05-4-sets.rkt b/Examples/Old Module 05/05-4-sets.rkt deleted file mode 100644 index 03cdf59..0000000 --- a/Examples/Old Module 05/05-4-sets.rkt +++ /dev/null @@ -1,102 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname sets) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -;; sets -(require rackunit) - -(require "extras.rkt") - -; (provide my-member? subset? set-equal?) -; (provide set-cons set-union) - -;; A SetOfX is a ListOfX with no duplicates - -;; note: empty is a SetOfX - -;; my-member? : X SetOfX -> Boolean -;; GIVEN: an X and a set of X's -;; RETURNS: true iff the X is an element of the set -;; STRATEGY: Use HOF ormap on set1 - -#;(define (my-member? x set1) - (local - ((define (test elt) (equal? x elt))) - (ormap test set1))) - -(define (my-member? x set1) - (ormap - (lambda (elt) (equal? x elt)) - set1)) - - -(begin-for-test - (check-true (my-member? 3 (list 1 3 5))) - (check-false (my-member? 4 (list 1 3 5))) -) - -;; subset? : SetOfX SetOfX -> Boolean -;; STRATEGY: Use HOF andmap on set1 - -#;(define (subset? set1 set2) - (local - ((define (test elt) (my-member? elt set2))) - (andmap test set1))) - -(define (subset? set1 set2) - (andmap - (lambda (elt) (my-member? elt set2)) - set1)) - -(begin-for-test - (check-true (subset? (list 1 3 5) (list 1 3 2 4 5 8))) - (check-false (subset? (list 1 3 5) (list 1 3 8)))) - -;; set-equal? : SetOfX SetOfX -> Boolean -;; STRATEGY: Call simpler functions -(define (set-equal? set1 set2) - (and - (subset? set1 set2) - (subset? set2 set1))) - -(begin-for-test - (check-true (set-equal? (list 1 3 5) (list 3 5 1))) - (check-false (set-equal? (list 1 3 5) (list 1 3 4 5))) - (check-false (set-equal? (list 1 3 5) (list 1 3 5 7))) - (check-false (set-equal? (list 1 3 5 7) (list 1 3 5)))) - -;; set-cons : X SetOfX -> SetOfX -;; STRATEGY: Cases on whether x is a member of set1 -(define (set-cons x set1) - (if (my-member? x set1) - set1 - (cons x set1))) - -(begin-for-test - (check set-equal? (set-cons 1 (list 3 5 7)) (list 3 1 5 7)) - (check set-equal? (set-cons 3 (list 3 5 7)) (list 5 3 7)) -) - -;; set-union : SetOfX SetOfX -> SetOfX -;; STRATEGY: use template for SetofX on set1 -#;(define (set-union set1 set2) - (cond - [(empty? set1) set2] - [else (set-cons - (first set1) - (set-union (rest set1) set2))])) - -;; STRATEGY: Use HOF foldr on set1 -(define (set-union set1 set2) - (foldr - set-cons - set2 - set1)) - -(begin-for-test - (check set-equal? - (set-union (list 1 3 5) (list 2 4 3 5 8)) - (list 1 2 3 4 5 8))) - - - - diff --git a/Examples/Old Module 05/05-emails.scm b/Examples/Old Module 05/05-emails.scm deleted file mode 100644 index e60ad60..0000000 --- a/Examples/Old Module 05/05-emails.scm +++ /dev/null @@ -1,67 +0,0 @@ -;;; Program to write email messages informing students of their pairing -;;; for Problem Sets 06 through 08. -;;; -;;; This program is written in Scheme, not in Racket. - -(import (scheme base) - (scheme read) - (scheme write) - (scheme file)) - -(define boilerplate1 - '("For CS 5010 Problem Sets 06 through 08, your partner will be\n" - "the student whose CCIS ID is\n\n ")) - -(define boilerplate2 - '("\n\nYou should be able to contact him or her " - "by sending email to\n\n ")) - -(define boilerplate3 - '("\n\nYou can learn his or her name by running the finger command on\n" - "any CCIS Linux machine:\n\n finger ")) - -(define boilerplate4 - '("\n\nReminder: You are not allowed to discuss Problem Set 05 with\n" - "anyone, including your new partner.\n\nWill\n")) - -;;; write-message : Symbol Symbol -> void -;;; GIVEN: two CCIS IDs id1, id2 -;;; EFFECT: uses id1 to name a newly created file in the current directory -;;; that tells student id1 his/her partner will be student id2 - -(define (write-message id1 id2) - (call-with-output-file - (symbol->string id1) - (lambda (q) (write-message-to-port q id1 id2)))) - -;;; write-message-to-port : TextualOutputPort Symbol Symbol -> void -;;; GIVEN: an output port and two CCIS IDs id1 and id2 -;;; EFFECT: writes a message to the port telling student id1 his/her -;;; partner will be student id2 - -(define (write-message-to-port out id1 id2) - (let ((display (lambda (x) (display x out)))) - (for-each display boilerplate1) - (display id2) - (for-each display boilerplate2) - (display id2) - (display "@ccs.neu.edu") - (for-each display boilerplate3) - (display id2) - (for-each display boilerplate4))) - -;;; write-messages : TextualInputPort -> void -;;; Given an input port from which the CCIS IDs of successive pairs -;;; can be read as symbols, creates an email message for each student -;;; in the current directory. - -(define (write-messages p) - (let* ((id1 (read p)) - (id2 (read p))) - (if (and (symbol? id1) - (symbol? id2)) - (begin (write-message id1 id2) - (write-message id2 id1) - (write-messages p))))) - -(call-with-input-file "../pairings1.txt" write-messages) diff --git a/Examples/Old Module 06/06-1-recursive-structures.rkt b/Examples/Old Module 06/06-1-recursive-structures.rkt deleted file mode 100644 index c1b40a7..0000000 --- a/Examples/Old Module 06/06-1-recursive-structures.rkt +++ /dev/null @@ -1,23 +0,0 @@ -(define-struct plain-pizza ()) -(define-struct topped-pizza (topping base)) - -;; A Topping is a String. -;; A Pizza is either -;; -- (make-plain-pizza) -;; -- (make-topped-pizza Topping Pizza) - -;; Interp: -;; (make-plain-pizza) represents a pizza with no toppings -;; (make-topped-pizza t p) represents the pizza p with topping t added on top. - - -#| -pizza-fn : Pizza -> ?? -Halting Measure: number of toppings -(define (pizza-fn p) - (cond - [(plain-pizza? p) ...] - [else (... (topped-pizza-topping p) - (pizza-fn - (topped-pizza-base p)))])) -|# diff --git a/Examples/Old Module 06/06-2-trees.rkt b/Examples/Old Module 06/06-2-trees.rkt deleted file mode 100644 index 934017c..0000000 --- a/Examples/Old Module 06/06-2-trees.rkt +++ /dev/null @@ -1,46 +0,0 @@ -;; 06-2-trees.rkt - -(define-struct leaf (datum)) -(define-struct node (lson rson)) - -;; A Tree is either -;; -- (make-leaf Number) -;; -- (make-node Tree Tree) - -#| -tree-fn : Tree -> ??? -HALTING MEASURE: number of nodes in t -(define (tree-fn t) - (cond - [(leaf? t) (... (leaf-datum t))] - [else (... - (tree-fn (node-lson t)) - (tree-fn (node-rson t)))])) -|# - -;; leaf-sum : Tree -> Number -;; STRATEGY: Use template for Tree on t -(define (leaf-sum t) - (cond - [(leaf? t) (leaf-datum t)] - [else (+ - (leaf-sum (node-lson t)) - (leaf-sum (node-rson t)))])) - -;; leaf-max : Tree -> Number -;; STRATEGY: Use template for Tree on t -(define (leaf-max t) - (cond - [(leaf? t) (leaf-datum t)] - [else (max - (leaf-max (node-lson t)) - (leaf-max (node-rson t)))])) - -;; leaf-min : Tree -> Number -;; STRATEGY: Use template for Tree on t -(define (leaf-min t) - (cond - [(leaf? t) (leaf-datum t)] - [else (min - (leaf-min (node-lson t)) - (leaf-min (node-rson t)))])) diff --git a/Examples/Old Module 06/06-3-lasns.rkt b/Examples/Old Module 06/06-3-lasns.rkt deleted file mode 100644 index 50be6e1..0000000 --- a/Examples/Old Module 06/06-3-lasns.rkt +++ /dev/null @@ -1,40 +0,0 @@ -;; A ListOfAlternatingNumbersAndStrings (LANS) is one of: -;; -- empty -;; -- (cons Number LASN) - -;; A ListOfAlternatingStringsAndNumbers (LASN) is one of: -;; -- empty -;; -- (cons String LANS) - -;; HALTING MEASURE: length of lans or lasn -;; lans-fn : LANS -> ?? -;; (define (lans-fn lans) -;; (cond -;; [(empty? lans) ...] -;; [else (... -;; (first lans) -;; (lasn-fn (rest lans)))])) - -;; lasn-fn : LASN -> ?? -;; (define (lasn-fn lasn) -;; (cond -;; [(empty? lasn) ...] -;; [else (... -;; (first lasn) -;; (lans-fn (rest lasn)))])) - -;; strategy: Use template for LANS/LASN on lans -;; lans-sum : LANS -> Number -(define (lans-sum lans) - (cond - [(empty? lans) 0] - [else (+ - (first lans) - (lasn-sum (rest lans)))])) - -;; lasn-sum : LASN -> Number -(define (lasn-sum lasn) - (cond - [(empty? lasn) 0] - [else (lans-sum (rest lasn))])) - diff --git a/Examples/Old Module 06/06-3-tree-folds.rkt b/Examples/Old Module 06/06-3-tree-folds.rkt deleted file mode 100644 index b1feb42..0000000 --- a/Examples/Old Module 06/06-3-tree-folds.rkt +++ /dev/null @@ -1,83 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; TREES -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define-struct leaf (datum)) -(define-struct node (lson rson)) - -;; A Tree is either -;; -- (make-leaf Number) -;; -- (make-node Tree Tree) - -#| -tree-fn : Tree -> ??? -(define (tree-fn t) - (cond - [(leaf? t) (... (leaf-datum t))] - [else (... - (tree-fn (node-lson t)) - (tree-fn (node-rson t)))])) -|# - -;; tree-fold : (X X -> X) (Number -> X) Tree -> X -;; STRATEGY: Use template for Tree on t -(define (tree-fold combiner base t) - (cond - [(leaf? t) (base (leaf-datum t))] - [else (combiner - (tree-fold combiner base - (node-lson t)) - (tree-fold combiner base - (node-rson t)))])) - -;; STRATEGY: Use HOF tree-fold on t -(define (tree-sum t) - (tree-fold + (lambda (n) n) t)) - -;; STRATEGY: Use HOF tree-fold on t -(define (tree-min t) - (tree-fold min (lambda (n) n) t)) - -;; STRATEGY: Use HOF tree-fold on t -(define (tree-max t) - (tree-fold max (lambda (n) n) t)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; ancestor trees -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define-struct adam ()) -(define-struct eve () -(define-struct person (name father mother)) - -;; A Person is either -;; -- (make-adam) -;; -- (make-eve) -;; -- (make-person String Person Person) - -#| -;; person-fn : Person -> ??? -(define (person-fn p) - (cond - [(adam? p) ...] - [(eve? p) ...] - [else (... - (person-name p) - (person-fn (person-father p)) - (person-fn (person-mother p)))])) -|# - -;; person-fold -;; : X X (String X X -> X) Person -> X -(define (person-fold adam-val eve-val combiner p) - (cond - [(adam? p) adam-val] - [(eve? p) eve-val] - [else (combiner - (person-name p) - (person-fold adam-val eve-val combiner - (person-father p)) - (person-fold adam-val eve-val combiner - (person-mother p)))])) - - diff --git a/Examples/Old Module 06/06-4-lasns.rkt b/Examples/Old Module 06/06-4-lasns.rkt deleted file mode 100644 index 50be6e1..0000000 --- a/Examples/Old Module 06/06-4-lasns.rkt +++ /dev/null @@ -1,40 +0,0 @@ -;; A ListOfAlternatingNumbersAndStrings (LANS) is one of: -;; -- empty -;; -- (cons Number LASN) - -;; A ListOfAlternatingStringsAndNumbers (LASN) is one of: -;; -- empty -;; -- (cons String LANS) - -;; HALTING MEASURE: length of lans or lasn -;; lans-fn : LANS -> ?? -;; (define (lans-fn lans) -;; (cond -;; [(empty? lans) ...] -;; [else (... -;; (first lans) -;; (lasn-fn (rest lans)))])) - -;; lasn-fn : LASN -> ?? -;; (define (lasn-fn lasn) -;; (cond -;; [(empty? lasn) ...] -;; [else (... -;; (first lasn) -;; (lans-fn (rest lasn)))])) - -;; strategy: Use template for LANS/LASN on lans -;; lans-sum : LANS -> Number -(define (lans-sum lans) - (cond - [(empty? lans) 0] - [else (+ - (first lans) - (lasn-sum (rest lans)))])) - -;; lasn-sum : LASN -> Number -(define (lasn-sum lasn) - (cond - [(empty? lasn) 0] - [else (lans-sum (rest lasn))])) - diff --git a/Examples/Old Module 06/06-4-sos-and-loss.rkt b/Examples/Old Module 06/06-4-sos-and-loss.rkt deleted file mode 100644 index c16c791..0000000 --- a/Examples/Old Module 06/06-4-sos-and-loss.rkt +++ /dev/null @@ -1,114 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 06-5-sos-and-loss) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -(require rackunit) -(require "extras.rkt") - -;; S-expressions -;; -;; An Sexp-of-String (SoS) is either -;; -- a String -;; -- a List-of SoS -;; -;; A List-of SoS (LoSS) is either -;; -- empty -;; -- (cons SoS LoSS) -;; -;; SoS's: -;; -;; "abcd" -;; "def" -;; ("abcd" "def") -;; ("abcd" ("abcd" "def")) -;; ("abc" "def" "ghi") -;; (("abc" "def" "ghi") -;; ("abcd" ("abcd" "def")) -;; "def" -;; ("abcd" "def")) -;; -;; Template: -;; -;; sos-fn : SoS -> ?? -;; loss-fn : LoSS -> ?? -;; -;; (define (sos-fn sos) -;; (cond -;; [(string? sos) ...] -;; [else (... (loss-fn sos))])) -;; -;; (define (loss-fn loss) -;; (cond -;; [(empty? loss) ...] -;; [else (... (sos-fn (first loss)) -;; (loss-fn (rest loss)) ...)])) -;; - -;; occurs-in? : Sos String -> Boolean -;; RETURNS: true if the given string occurs somewhere in the given sos. -;; occurs-in-loss? : Loss String -> Boolean -;; RETURNS: true if the given string occurs somewhere in the given loss. -;; STRATEGY: Use templates for SoS and LoSS - -(define (occurs-in? sos str) - (cond - [(string? sos) (string=? sos str)] - [else (occurs-in-loss? sos str)])) - -(define (occurs-in-loss? loss str) - (cond - [(empty? loss) false] - [else (or (occurs-in? (first loss) str) - (occurs-in-loss? (rest loss) str))])) - -(begin-for-test - - (check-equal? (occurs-in? "alice" "alice") true) - (check-equal? (occurs-in? "bob" "alice") false) - - (check-equal? - (occurs-in? (list "alice" "bob") "cathy") - false) - - (check-equal? - (occurs-in? - (list - (list "alice" "bob") - "carole") - "bob") - true) - - (check-equal? - (occurs-in? - (list "alice" - (list (list "alice" "bob") "dave") - "eve") - "bob") - true)) - -;; number-of-strings : Sos -> Number -;; number-of-strings-in-loss : Loss -> Number -;; RETURNS: the number of strings in the given sos or loss. -;; STRATEGY: Use templates for SoS and LoSS - -(define (number-of-strings sos) - (cond - [(string? sos) 1] - [else (number-of-strings-in-loss sos)])) - -(define (number-of-strings-in-loss loss) - (cond - [(empty? loss) 0] - [else (+ (number-of-strings (first loss)) - (number-of-strings-in-loss (rest loss)))])) - -(begin-for-test - - (check-equal? - (number-of-strings - (list "alice" - (list (list "alice" "bob") "dave") - "eve" - "bob")) - 6) - ) - diff --git a/Examples/Old Module 06/06-5-descendants.rkt b/Examples/Old Module 06/06-5-descendants.rkt deleted file mode 100644 index ed6b73a..0000000 --- a/Examples/Old Module 06/06-5-descendants.rkt +++ /dev/null @@ -1,106 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 06-5-descendants) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -;; descendants-better-tests.rkt - -(require rackunit) -(require rackunit/text-ui) - -(require "sets.rkt") -;; (require "extras.rkt") ; uncomment to get access to "provide" - - -(define-struct person (name children)) -;; A Person is a -;; (make-person String ListOfPersons) -;; Interp: (make-person str lst) represents a person whose name is str -;; and whose children are represented by lst - -;; A ListOfPersons (LoP) is one of -;; -- empty -;; -- (cons Person ListOfPersons) - -(define alice (make-person "alice" empty)) -(define bob (make-person "bob" empty)) -(define chuck (make-person "chuck" (list alice bob))) - -(define dave (make-person "dave" empty)) -(define eddie (make-person "eddie" (list dave))) - -(define fred (make-person "fred" (list chuck eddie))) - -;;;; Template: -;;;; person-fn : Person -> ?? -;;(define (person-fn p) -;; (... (person-name p) (lop-fn (person-children p)))) -;; -;;;; lop-fn : ListOfPersons -> ?? -;;(define (lop-fn lop) -;; (cond -;; [(empty? lop) ...] -;; [else (... (person-fn (first p)) -;; (lop-fn (rest p)))])) - - -;; grandchildren : Person -> LoP -;; RETURNS: a list of the grandchildren of the given person. -;; (grandchildren fred) = (list alice bob dave) -;; STRATEGY: Use template for Person/LoP - -(define (grandchildren p) - (all-children (person-children p))) - -;; all-children : LoP -> LoP -;; GIVEN: a list of persons, -;; RETURNS: the list of all their children. -;; (all-children (list fred eddie)) = (list chuck eddie dave) -;; STRATEGY: Use template for Person/LoP - -(define (all-children lop) - (cond - [(empty? lop) empty] - [else (append - (person-children (first lop)) - (all-children (rest lop)))])) - -(define-test-suite grandchildren-tests - (check set-equal? - (all-children (list fred eddie)) - (list chuck eddie dave)) - ;; same test, but with the answer in a different order - (check set-equal? - (all-children (list fred eddie)) - (list eddie chuck dave)) - (check set-equal? - (grandchildren fred) - (list alice bob dave))) - - - -;; descendants : Person -> LoP -;; GIVEN: a Person, -;; RETURNS: the list of his/her descendants -;; all-descendants : LoP -> LoP -;; GIVEN: a ListOfPersons, -;; RETURNS: the list of all their descendants -;; (descendants fred) = (list chuck eddie alice bob dave) -;; (all-descendants (list chuck eddie)) = (list alice bob eddie) -;; STRATEGY: Use template for Person/LoP - -(define (descendants p) - (append - (person-children p) - (all-descendants (person-children p)))) - -(define (all-descendants lop) - (cond - [(empty? lop) empty] - [else (append - (descendants (first lop)) - (all-descendants (rest lop)))])) - -(begin-for-test - (check set-equal? (descendants fred) (list chuck eddie alice bob dave)) - (check set-equal? (all-descendants (list chuck eddie)) (list alice bob dave))) - - diff --git a/Examples/Old Module 06/06-5-sos-derivation.rkt b/Examples/Old Module 06/06-5-sos-derivation.rkt deleted file mode 100644 index d5ba67d..0000000 --- a/Examples/Old Module 06/06-5-sos-derivation.rkt +++ /dev/null @@ -1,75 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 06-5-sos-and-loss) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -(require rackunit) -(require "extras.rkt") - -;; S-expressions -;; -;; An Sexp-of-String (SoS) is either -;; -- a String -;; -- a List-of SoS -;; -;; A List-of SoS (LoSS) is either -;; -- empty -;; -- (cons SoS LoSS) -;; -;; SoS's: -;; -;; "abcd" -;; "def" -;; ("abcd" "def") -;; ("abcd" ("abcd" "def")) -;; ("abc" "def" "ghi") -;; (("abc" "def" "ghi") -;; ("abcd" ("abcd" "def")) -;; "def" -;; ("abcd" "def")) -;; - -#| -Derivation of (("alice" "bob") "carole") - -In list notation, this is - -(list (list "alice" "bob") "carole") - -In cons notation, it becomes -(cons - (cons "alice" (cons "bob" empty)) - (cons "carole" - empty)) - -This is - -SoS --> LoSS --> (cons SoS LoSS) --> (cons LoSS LoSS) --> (cons (cons SoS LoSS) - LoSS) --> (cons (cons SoS LoSS) - LoSS) --> (cons (cons String LoSS) - LoSS) --> (cons (cons "alice" LoSS) - LoSS) --> (cons (cons "alice" (cons SoS LoSS)) - LoSS) --> (cons (cons "alice" (cons String LoSS)) - LoSS) --> (cons (cons "alice" (cons "bob" LoSS)) - LoSS) --> (cons (cons "alice" (cons "bob" empty)) - LoSS) --> (cons (cons "alice" (cons "bob" empty)) - (cons SoS LoSS)) --> (cons (cons "alice" (cons "bob" empty)) - (cons String LoSS)) --> (cons (cons "alice" (cons "bob" empty)) - (cons "carole" LoSS)) --> (cons (cons "alice" (cons "bob" empty)) - (cons "carole" empty)) - -15 steps! -|# diff --git a/Examples/Old Module 06/06-6-sos-and-loss.rkt b/Examples/Old Module 06/06-6-sos-and-loss.rkt deleted file mode 100644 index c16c791..0000000 --- a/Examples/Old Module 06/06-6-sos-and-loss.rkt +++ /dev/null @@ -1,114 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 06-5-sos-and-loss) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -(require rackunit) -(require "extras.rkt") - -;; S-expressions -;; -;; An Sexp-of-String (SoS) is either -;; -- a String -;; -- a List-of SoS -;; -;; A List-of SoS (LoSS) is either -;; -- empty -;; -- (cons SoS LoSS) -;; -;; SoS's: -;; -;; "abcd" -;; "def" -;; ("abcd" "def") -;; ("abcd" ("abcd" "def")) -;; ("abc" "def" "ghi") -;; (("abc" "def" "ghi") -;; ("abcd" ("abcd" "def")) -;; "def" -;; ("abcd" "def")) -;; -;; Template: -;; -;; sos-fn : SoS -> ?? -;; loss-fn : LoSS -> ?? -;; -;; (define (sos-fn sos) -;; (cond -;; [(string? sos) ...] -;; [else (... (loss-fn sos))])) -;; -;; (define (loss-fn loss) -;; (cond -;; [(empty? loss) ...] -;; [else (... (sos-fn (first loss)) -;; (loss-fn (rest loss)) ...)])) -;; - -;; occurs-in? : Sos String -> Boolean -;; RETURNS: true if the given string occurs somewhere in the given sos. -;; occurs-in-loss? : Loss String -> Boolean -;; RETURNS: true if the given string occurs somewhere in the given loss. -;; STRATEGY: Use templates for SoS and LoSS - -(define (occurs-in? sos str) - (cond - [(string? sos) (string=? sos str)] - [else (occurs-in-loss? sos str)])) - -(define (occurs-in-loss? loss str) - (cond - [(empty? loss) false] - [else (or (occurs-in? (first loss) str) - (occurs-in-loss? (rest loss) str))])) - -(begin-for-test - - (check-equal? (occurs-in? "alice" "alice") true) - (check-equal? (occurs-in? "bob" "alice") false) - - (check-equal? - (occurs-in? (list "alice" "bob") "cathy") - false) - - (check-equal? - (occurs-in? - (list - (list "alice" "bob") - "carole") - "bob") - true) - - (check-equal? - (occurs-in? - (list "alice" - (list (list "alice" "bob") "dave") - "eve") - "bob") - true)) - -;; number-of-strings : Sos -> Number -;; number-of-strings-in-loss : Loss -> Number -;; RETURNS: the number of strings in the given sos or loss. -;; STRATEGY: Use templates for SoS and LoSS - -(define (number-of-strings sos) - (cond - [(string? sos) 1] - [else (number-of-strings-in-loss sos)])) - -(define (number-of-strings-in-loss loss) - (cond - [(empty? loss) 0] - [else (+ (number-of-strings (first loss)) - (number-of-strings-in-loss (rest loss)))])) - -(begin-for-test - - (check-equal? - (number-of-strings - (list "alice" - (list (list "alice" "bob") "dave") - "eve" - "bob")) - 6) - ) - diff --git a/Examples/Old Module 06/06-7-descendants.rkt b/Examples/Old Module 06/06-7-descendants.rkt deleted file mode 100644 index e11d95e..0000000 --- a/Examples/Old Module 06/06-7-descendants.rkt +++ /dev/null @@ -1,106 +0,0 @@ -;; The first three lines of this file were inserted by DrRacket. They record metadata -;; about the language level of this file in a form that our tools can easily process. -#reader(lib "htdp-beginner-reader.ss" "lang")((modname 06-2-descendants) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ()))) -;; descendants-better-tests.rkt - -(require rackunit) -(require rackunit/text-ui) - -(require "sets.rkt") -;; (require "extras.rkt") ; uncomment to get access to "provide" - - -(define-struct person (name children)) -;; A Person is a -;; (make-person String ListOfPersons) -;; Interp: (make-person str lst) represents a person whose name is str -;; and whose children are represented by lst - -;; A ListOfPersons (LoP) is one of -;; -- empty -;; -- (cons Person ListOfPersons) - -(define alice (make-person "alice" empty)) -(define bob (make-person "bob" empty)) -(define chuck (make-person "chuck" (list alice bob))) - -(define dave (make-person "dave" empty)) -(define eddie (make-person "eddie" (list dave))) - -(define fred (make-person "fred" (list chuck eddie))) - -;;;; Template: -;;;; person-fn : Person -> ?? -;;(define (person-fn p) -;; (... (person-name p) (lop-fn (person-children p)))) -;; -;;;; lop-fn : ListOfPersons -> ?? -;;(define (lop-fn lop) -;; (cond -;; [(empty? lop) ...] -;; [else (... (person-fn (first p)) -;; (lop-fn (rest p)))])) - - -;; grandchildren : Person -> LoP -;; RETURNS: a list of the grandchildren of the given person. -;; (grandchildren fred) = (list alice bob dave) -;; STRATEGY: Use template for Person/LoP - -(define (grandchildren p) - (all-children (person-children p))) - -;; all-children : LoP -> LoP -;; GIVEN: a list of persons, -;; RETURNS: the list of all their children. -;; (all-children (list fred eddie)) = (list chuck eddie dave) -;; STRATEGY: Use template for Person/LoP - -(define (all-children lop) - (cond - [(empty? lop) empty] - [else (append - (person-children (first lop)) - (all-children (rest lop)))])) - -(define-test-suite grandchildren-tests - (check set-equal? - (all-children (list fred eddie)) - (list chuck eddie dave)) - ;; same test, but with the answer in a different order - (check set-equal? - (all-children (list fred eddie)) - (list eddie chuck dave)) - (check set-equal? - (grandchildren fred) - (list alice bob dave))) - - - -;; descendants : Person -> LoP -;; GIVEN: a Person, -;; RETURNS: the list of his/her descendants -;; all-descendants : LoP -> LoP -;; GIVEN: a ListOfPersons, -;; RETURNS: the list of all their descendants -;; (descendants fred) = (list chuck eddie alice bob dave) -;; (all-descendants (list chuck eddie)) = (list alice bob eddie) -;; STRATEGY: Use template for Person/LoP - -(define (descendants p) - (append - (person-children p) - (all-descendants (person-children p)))) - -(define (all-descendants lop) - (cond - [(empty? lop) empty] - [else (append - (descendants (first lop)) - (all-descendants (rest lop)))])) - -(begin-for-test - (check set-equal? (descendants fred) (list chuck eddie alice bob dave)) - (check set-equal? (all-descendants (list chuck eddie)) (list alice bob dave))) - - \ No newline at end of file diff --git a/Examples/Old Module 06/06-7-tree-folds.rkt b/Examples/Old Module 06/06-7-tree-folds.rkt deleted file mode 100644 index b1feb42..0000000 --- a/Examples/Old Module 06/06-7-tree-folds.rkt +++ /dev/null @@ -1,83 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; TREES -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define-struct leaf (datum)) -(define-struct node (lson rson)) - -;; A Tree is either -;; -- (make-leaf Number) -;; -- (make-node Tree Tree) - -#| -tree-fn : Tree -> ??? -(define (tree-fn t) - (cond - [(leaf? t) (... (leaf-datum t))] - [else (... - (tree-fn (node-lson t)) - (tree-fn (node-rson t)))])) -|# - -;; tree-fold : (X X -> X) (Number -> X) Tree -> X -;; STRATEGY: Use template for Tree on t -(define (tree-fold combiner base t) - (cond - [(leaf? t) (base (leaf-datum t))] - [else (combiner - (tree-fold combiner base - (node-lson t)) - (tree-fold combiner base - (node-rson t)))])) - -;; STRATEGY: Use HOF tree-fold on t -(define (tree-sum t) - (tree-fold + (lambda (n) n) t)) - -;; STRATEGY: Use HOF tree-fold on t -(define (tree-min t) - (tree-fold min (lambda (n) n) t)) - -;; STRATEGY: Use HOF tree-fold on t -(define (tree-max t) - (tree-fold max (lambda (n) n) t)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; ancestor trees -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define-struct adam ()) -(define-struct eve () -(define-struct person (name father mother)) - -;; A Person is either -;; -- (make-adam) -;; -- (make-eve) -;; -- (make-person String Person Person) - -#| -;; person-fn : Person -> ??? -(define (person-fn p) - (cond - [(adam? p) ...] - [(eve? p) ...] - [else (... - (person-name p) - (person-fn (person-father p)) - (person-fn (person-mother p)))])) -|# - -;; person-fold -;; : X X (String X X -> X) Person -> X -(define (person-fold adam-val eve-val combiner p) - (cond - [(adam? p) adam-val] - [(eve? p) eve-val] - [else (combiner - (person-name p) - (person-fold adam-val eve-val combiner - (person-father p)) - (person-fold adam-val eve-val combiner - (person-mother p)))])) - - diff --git a/Examples/Old Module 06/06-8-grammars.rkt b/Examples/Old Module 06/06-8-grammars.rkt deleted file mode 100644 index 3d9f83a..0000000 --- a/Examples/Old Module 06/06-8-grammars.rkt +++ /dev/null @@ -1,118 +0,0 @@ -;;; A Data Definition is a grammar - - -Data Definition: - -A ListOfString is either --- empty --- (cons String ListOfString) - -Context-Free Grammar: - -ListOfString -> empty -ListOfString -> (cons String ListOfString) - -Example: - -ListOfString --> (cons String ListOfString) --> (cons "Marvin" ListOfString) --> (cons "Marvin" (cons String ListOfString)) --> (cons "Marvin" (cons String empty)) --> (cons "Marvin" (cons "Rahul" empty)) - -5 Steps - -A BinaryTree is either --- (make-leaf Number) --- (make-node BinaryTree BinaryTree) - - -BinaryTree --> (make-node BinaryTree BinaryTree) --> (make-node (make-node BinaryTree BinaryTree) - BinaryTree) --> (make-node (make-node (make-leaf Number) BinaryTree) - BinaryTree) --> (make-node (make-node (make-leaf 100) BinaryTree) - BinaryTree) --> (make-node (make-node (make-leaf 100) (make-leaf Number)) - BinaryTree) --> (make-node (make-node (make-leaf 100) (make-leaf 200)) - BinaryTree) --> (make-node (make-node (make-leaf 100) (make-leaf 200)) - (make-node Number)) --> (make-node (make-node (make-leaf 100) (make-leaf 200)) - (make-node 300)) - -8 steps - -If it takes x steps to build t1 and y steps to build t2, -then it takes x+y+1 steps to build (make-node t1 t2) : - -BinaryTree --> (make-node BinaryTree BinaryTree) --> ... {x steps} --> (make-node t1 BinaryTree) --> ... {y steps} --> (make-node t1 t2) - -Let steps(t) denote the number of steps it takes to build t. -Then steps(node-lson t) < steps(t) -and steps(node-rson t) < steps(t) - -So if we have a function following the template - -(define (tree-fn t) - (cond - [(leaf? t) ...] - [else (... (tree-fn (node-lson t)) - (tree-fn (node-rson t)))])) - -steps(t) is a halting measure for tree-fn. - -==================================================== - -The same idea works for SoS and LoSS: - -Data Definition: - -An S-expression of Strings (SoS) is either --- a String --- a List of SoS's (LoSS) - -A List of SoS's (LoSS) is either --- empty --- (cons SoS LoSS) - -Grammar: - -SoS -> String -SoS -> LoSS -LoSS -> empty -LoSS -> (cons SoS LoSS) - -{repeat example} - -If it takes k steps to get from LoSS to lst, then it takes k+1 steps -to get from SoS to lst: - -SoS -> LoSS -> ...{k steps} -> lst - -If it takes k1 steps to get from SoS to s -and k2 steps to get from LoSS to lst -then it takes k1+k2+1 steps to get from LoSS to (cons s lst) - -LoSS --> (cons SoS LoSS) --> {k1 steps} --> (cons s LoSS) --> {k2 steps} --> (cons s lst) - -Let's look at the template function: - - - - - diff --git a/Examples/bst.ps11 b/Examples/bst.ps11 deleted file mode 100644 index 3201f59..0000000 --- a/Examples/bst.ps11 +++ /dev/null @@ -1,171 +0,0 @@ -# Binary search tree benchmark. -# -# Creates a binary search tree of size n, using 0 through n-1 as keys -# and their squares as values. Then searches for k the number of times -# specified by repeat, returning the square of k. - -bstBenchmark (n, k, repeat) - doSearches (makeTree (n), k, repeat); - -doSearches (t, k, repeat) - if repeat < 2 - then lookup (k, t, notFound) - else (λ (val) doSearches (t, k, repeat - 1)) - (lookup (k, t, notFound)); - -# Returns the value associated with k in t, -# or returns notFound if k is not a key in t. - -lookup (k, t, notFound) - if isEmpty (t) - then notFound - else (λ (k0) - if k = k0 - then rootValue (t) - else if k < k0 - then lookup (k, left (t), notFound) - else lookup (k, right (t), notFound) - - ) - (rootKey (t)); - -# Returns a binary search tree of size n whose keys are 0 through n-1, -# with each key mapped to its square. -# Adding those keys in sorted order would create an unbalanced tree, -# so they're added in a more scattered order. - -makeTree (n) - if n > 2 - then populateTree (emptyTree, 0, n, suitableStride (n)) - else if n = 2 - then insert (0, 0, insert (1, 1, emptyTree)) - else if n = 1 - then insert (0, 0, emptyTree) - else emptyTree; - -# Given a tree t of the given size, a desired size n, and -# an integer k that is coprime to n, -# returns a tree of size n, whose keys are the integers in [0,n) -# that maps each key to its square. - -populateTree (t, size, n, k) - if size = n - then checkTree (t, n) - else (λ (key) - populateTree (insert (key, key * key, t), size + 1, n, k)) - (mod (size * k, n)); - -# Checks to make sure all keys in [0,n) are present. -# If that is so, returns the tree. - -checkTree (t, n) - if n = 0 - then t - else if lookup (n - 1, t, notFound) < notFound - then checkTree (t, n - 1) - else false + false; - -# Precondition: n > 0. -# Returns an integer in the range [0,n) that's coprime to n. - -suitableStride (n) - suitableStrideLoop (n, div (n, 3)); - -suitableStrideLoop (n, k) - if gcd (n, k) = 1 - then k - else suitableStrideLoop (n, k + 1); - -# Precondition: k is non-negative, and n is positive. -# Returns the integer quotient of k divided by n. - -div (k, n) - if k < n - then 0 - else 1 + div (k - n, n); - -# Precondition: k is non-negative, and n is positive. -# Returns k modulo n. - -mod (k, n) - if k < n - then k - else mod (k - n, n); - -# Precondition: both arguments are 1 or greater. -# Returns their greatest common denominator. - -gcd (i, j) - if i = j - then i - else if i > j - then gcd (i - j, j) - else gcd (i, j - i); - -################################################################ -# -# Abstract data type of binary search trees, -# with integers as keys and values arbitrary. -# -# Representation: -# A tree takes a 5-argument function and returns the result -# of calling that function on these values: -# a boolean indicating whether the tree is empty -# the key at the root (non-empty only) -# the value at the root (non-empty only) -# the left subtree (non-empty only) -# the right subtree (non-empty only) -# -################################################################ - -emptyTree (f) - f (true, false, false, false, false); - -newTree (key, value, left, right) - (λ (f) f (false, key, value, left, right)); - -isEmpty (t) - t ((λ (isEmpty, key, value, left, right) isEmpty)); - -rootKey (t) - t ((λ (isEmpty, key, value, left, right) key)); - -rootValue (t) - t ((λ (isEmpty, key, value, left, right) value)); - -left (t) - t ((λ (isEmpty, key, value, left, right) left)); - -right (t) - t ((λ (isEmpty, key, value, left, right) right)); - -insert (key, value, t) - if isEmpty (t) - then newTree (key, value, t, t) - else if key = rootKey (t) - then newTree (key, value, left (t), right (t)) - else if key < rootKey (t) - then newTree (rootKey (t), - rootValue (t), - insert (key, value, left (t)), - right (t)) - else newTree (rootKey (t), - rootValue (t), - left (t), - insert (key, value, right (t))); - -lookup (key, t, notFound) - if isEmpty (t) - then notFound - else if key = rootKey (t) - then rootValue (t) - else if key < rootKey (t) - then lookup (key, left (t), notFound) - else lookup (key, right (t), notFound); - -size (t) - if isEmpty (t) - then 0 - else 1 + size (left (t)) + size (right (t)); - -notFound = 1000000000000000000 diff --git a/Examples/church.ps11 b/Examples/church.ps11 deleted file mode 100644 index f5ebfe3..0000000 --- a/Examples/church.ps11 +++ /dev/null @@ -1,85 +0,0 @@ -# Church numerals -# -# The natural number n is represented by the function that -# takes a unary function f and returns f^n (the unary function -# that applies f n times). - -# Factorial function using Church numerals. -# Converts input to a Church numeral, does the computation -# using Church numerals, and converts back to the native -# representation of integers for output. - -fact (n) dechurch (f (church (n))); - -# Given a non-negative integer, returns its representation -# as a Church numeral. - -church (n) if n = 0 then zero else succ (church (n - 1)); - -# The Church numeral for 0 returns f^0, which is the identity function. - -zero (f) (λ (x) x); - -# The Church numeral for 1 is the successor of the Church numeral for 0. - -one (f) succ (zero) (f); - -# Given a Church numeral, returns its successor (the Church numeral -# for one plus the integer represented by the given Church numeral). - -succ (g) - (λ (f) - (λ (x) f (g (f) (x)))); - -# The predecessor function is complicated. - -pred (n) - (λ (f) - (λ (x) - n ((λ (g) (λ (h) h (g (f))))) - ((λ (g) x)) - ((λ (n) n)))); - -# Curried add. Given a Church numeral m, returns a function that, -# given a Church numeral n, returns the Church numeral for their sum. - -add (m) (λ (n) (λ (f) (λ (x) m (f) (n (f) (x))))); - -# Curried subtraction. The add function could have been written -# more simply, like this but with succ instead of pred. - -sub (m) (λ (n) m (pred) (n)); - -# mul (m) (n) could have been defined to return m (n). - -mul (m) (λ (n) (λ (f) m (n (f)))); - -# The isZero function returns a Church representation of true -# if and only if its argument is the Church numeral for zero; -# otherwise it returns a Church representation of false. - -isZero (m) m ((λ (x) fls)) (tru); - -# Church representation of false. - -fls (m) (λ (n) n); - -# Church representation of true. - -tru (m) (λ (n) m); - -# Factorial using Church numerals. -# The call to force and the (λ (z) ...) stuff is necessary -# because our interpreters implement call-by-value semantics. -# The (λ (z) ...) delays computation of ... until that computation -# is forced by the force function. - -f (n) force (isZero (n) ((λ (z) one)) ((λ (z) mul (n) (f (pred (n)))))); - -# Given a delayed computation, performs it. - -force (f) f (f); - -# Conversion from Church numeral to native integer. - -dechurch (f) f ((λ (f) f + 1)) (0) diff --git a/Examples/sieve.ps10 b/Examples/sieve.ps10 deleted file mode 100644 index 1f9466b..0000000 --- a/Examples/sieve.ps10 +++ /dev/null @@ -1,139 +0,0 @@ -# Given lo and hi, returns the number of prime numbers in the range [lo,hi]. - -primeCount (lo, hi) - length (primes (lo, hi)); - -# Given lo and hi, returns a list of the prime numbers in [lo,hi]. - -primes (lo, hi) - filter ((λ (p) inRange (p, lo, hi)), - primesThruN (hi)); - -# Precondition: lo <= hi. -# Returns true iff lo <= k <= hi. - -inRange (k, lo, hi) - if k < lo - then false - else if k > hi - then false - else true fi fi; - -# Returns a list of the prime numbers less than or equal to n. - -primesThruN (n) - sieve (rest (rest (naturalsThruN (n)))); - -# Returns a list of the natural numbers less than or equal to n. - -naturalsThruN (n) - (λ (loop) - loop (loop, n, empty)) - ((λ (loop, n, nums) - if n = 0 - then cons (0, nums) - else loop (loop, n - 1, cons (n, nums)) - fi)); - -# Sieve of Eratosthenes. -# Given a list of natural numbers whose first element is a prime, -# where the list contains all natural numbers greater than one -# (up through some limit) that are not divisible by a prime less than -# the first element, -# returns a list of all primes greater than or equal to the first -# element of the given list and less than or equal to the limit. - -sieve (lst) - if isEmpty (lst) - then empty - else (λ (p) - (cons (p, sieve (removeMultiples (p, lst))))) - (first (lst)) - fi; - -# Returns the list obtained by removing all multiples of k from lst. - -removeMultiples (k, lst) - removeMultiplesLoop (k, lst, k); - -# Precondition: m is a multiple of k, the list is sorted, -# and the list contains no multiples of k less than m. -# Returns the list obtained by removing all multiples of k from lst. - -removeMultiplesLoop (k, lst, m) - if isEmpty (lst) - then empty - else if m < first (lst) - then removeMultiplesLoop (k, lst, m + k) - else if m = first (lst) - then removeMultiplesLoop (k, rest (lst), m + k) - else cons (first (lst), - removeMultiplesLoop (k, rest (lst), m)) - fi fi fi; - -################################################################ -# -# Functions defined on lists. -# -################################################################ - -# Returns the length of the list. - -length (lst) - if isEmpty (lst) then 0 else 1 + length (rest (lst)) fi; - -# Returns a list of the given list's elements for which the -# given predicate is true. - -filter (pred, lst) - if isEmpty (lst) - then empty - else if pred (first (lst)) - then cons (first (lst), - filter (pred, rest (lst))) - else filter (pred, rest (lst)) - fi fi; - -################################################################ -# -# An abstract data type of lists. -# -# Representation: -# A list is a function that, given a 3-argument selector -# function, returns the result of calling that function on -# these three things: -# a boolean indicating whether the list is empty -# the first element of the list -# the rest of the list -# -################################################################ - -empty (op) # the empty list - op (true, empty, empty); - -cons (x, lst) # returns x consed onto lst - (λ (op) - (op (false, x, lst))); - -isEmpty (lst) # returns true iff lst is empty - lst ((λ (x, y, z) x)); - -first (lst) # returns first element of a non-empty lst - if isEmpty (lst) - then false + false # throws exception if lst is empty - else first0 (lst) - fi; - -rest (lst) # returns rest of a non-empty lst - if isEmpty (lst) - then false + false # throws exception if lst is empty - else rest0 (lst) - fi; - -# Private help functions. - -first0 (lst) # unsafe (non-checking) version of first - lst ((λ (x, y, z) y)); - -rest0 (lst) # unsafe (non-checking) version of rest - lst ((λ (x, y, z) z)) diff --git a/Examples/sieve.ps11 b/Examples/sieve.ps11 deleted file mode 100644 index e3085d2..0000000 --- a/Examples/sieve.ps11 +++ /dev/null @@ -1,133 +0,0 @@ -# Given lo and hi, returns the number of prime numbers in the range [lo,hi]. - -primeCount (lo, hi) - length (primes (lo, hi)); - -# Given lo and hi, returns a list of the prime numbers in [lo,hi]. - -primes (lo, hi) - filter ((λ (p) inRange (p, lo, hi)), - primesThruN (hi)); - -# Precondition: lo <= hi. -# Returns true iff lo <= k <= hi. - -inRange (k, lo, hi) - if k < lo - then false - else if k > hi - then false - else true; - -# Returns a list of the prime numbers less than or equal to n. - -primesThruN (n) - sieve (rest (rest (naturalsThruN (n)))); - -# Returns a list of the natural numbers less than or equal to n. - -naturalsThruN (n) - (λ (loop) - loop (loop, n, empty)) - ((λ (loop, n, nums) - if n = 0 - then cons (0, nums) - else loop (loop, n - 1, cons (n, nums)))); - -# Sieve of Eratosthenes. -# Given a list of natural numbers whose first element is a prime, -# where the list contains all natural numbers greater than one -# (up through some limit) that are not divisible by a prime less than -# the first element, -# returns a list of all primes greater than or equal to the first -# element of the given list and less than or equal to the limit. - -sieve (lst) - if isEmpty (lst) - then empty - else (λ (p) - (cons (p, sieve (removeMultiples (p, lst))))) - (first (lst)); - -# Returns the list obtained by removing all multiples of k from lst. - -removeMultiples (k, lst) - removeMultiplesLoop (k, lst, k); - -# Precondition: m is a multiple of k, the list is sorted, -# and the list contains no multiples of k less than m. -# Returns the list obtained by removing all multiples of k from lst. - -removeMultiplesLoop (k, lst, m) - if isEmpty (lst) - then empty - else if m < first (lst) - then removeMultiplesLoop (k, lst, m + k) - else if m = first (lst) - then removeMultiplesLoop (k, rest (lst), m + k) - else cons (first (lst), - removeMultiplesLoop (k, rest (lst), m)); - -################################################################ -# -# Functions defined on lists. -# -################################################################ - -# Returns the length of the list. - -length (lst) - if isEmpty (lst) then 0 else 1 + length (rest (lst)); - -# Returns a list of the given list's elements for which the -# given predicate is true. - -filter (pred, lst) - if isEmpty (lst) - then empty - else if pred (first (lst)) - then cons (first (lst), - filter (pred, rest (lst))) - else filter (pred, rest (lst)); - -################################################################ -# -# An abstract data type of lists. -# -# Representation: -# A list is a function that, given a 3-argument selector -# function, returns the result of calling that function on -# these three things: -# a boolean indicating whether the list is empty -# the first element of the list -# the rest of the list -# -################################################################ - -empty (op) # the empty list - op (true, empty, empty); - -cons (x, lst) # returns x consed onto lst - (λ (op) - (op (false, x, lst))); - -isEmpty (lst) # returns true iff lst is empty - lst ((λ (x, y, z) x)); - -first (lst) # returns first element of a non-empty lst - if isEmpty (lst) - then false + false # throws exception if lst is empty - else first0 (lst); - -rest (lst) # returns rest of a non-empty lst - if isEmpty (lst) - then false + false # throws exception if lst is empty - else rest0 (lst); - -# Private help functions. - -first0 (lst) # unsafe (non-checking) version of first - lst ((λ (x, y, z) y)); - -rest0 (lst) # unsafe (non-checking) version of rest - lst ((λ (x, y, z) z)) diff --git a/Examples/vectors.ps11 b/Examples/vectors.ps11 deleted file mode 100644 index bfa5e9f..0000000 --- a/Examples/vectors.ps11 +++ /dev/null @@ -1,39 +0,0 @@ -# Inner product of two vectors. -# -# Creates two vectors of length n, with elements 0 through n-1. -# Returns their inner product, which will be -# -# n^3/3 + n^2/2 + n/6 - -main (n) - innerProduct (makeVector (n, (λ (i) i)), - makeVector (n, (λ (i) i)), - n); - -# Given two vectors of length n, returns their inner product. - -innerProduct (v1, v2, n) - if n > 0 - then vref (v1, n-1) * vref (v2, n-1) + innerProduct (v1, v2, n - 1) - else 0; - -################################################################ -# -# Abstract data type of vectors. -# -# Representation: -# A vector is a finite function from valid indexes to values. -# -# With that representation, there is no way to extract the size -# of a vector. -# -################################################################ - -# Returns the vector of size n whose elements are obtained -# by calling f on the valid indexes. - -makeVector (n, f) f; # pretty simple, really - -# Returns element i of the vector. - -vref (v, i) v (i) diff --git a/GuidedPractices/gp07-2/solution.html b/GuidedPractices/gp07-2/solution.html index 20bcca3..3712a57 100644 --- a/GuidedPractices/gp07-2/solution.html +++ b/GuidedPractices/gp07-2/solution.html @@ -59,5 +59,5 @@

Guided Practice 7.2 (Solution)

-Last modified: Wed Oct 25 22:05:04 Eastern Daylight Time 2017 +Last modified: Mon Nov 13 20:00:12 Eastern Standard Time 2017 diff --git a/Inheritance/caseStudy1.html b/Inheritance/caseStudy1.html index d969124..8d91cd8 100644 --- a/Inheritance/caseStudy1.html +++ b/Inheritance/caseStudy1.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,63 +25,60 @@

Case Study: Immutable Finite Functions, Part 1 -

+

In this case study, we design and implement an immutable abstract data type of finite functions. -

+

- The IMap<K,V> interface extends - the Map<K,V> interface - defined in Java's java.util package. - That is possible only because all operations of - the Map<K,V> interface - that have side effects are optional: - classes that implement those optional operations - are allowed to implement them by defining methods - that throw an UnsupportedOperationException - if those methods are ever called. -

+ Our first implementation of that abstract data type + will represent a finite function as a list + of objects, each of which represents + a key and its associated value. + We will refer to these representations as + association lists, or + alists. +

- Our first implementation of the IMap<K,V> - interface relies on inheritance by extending two - abstract base classes defined in Java's java.util package: - AbstractMap<K,V> and - AbstractSet<K,V>. -

+ To reduce duplication of code, + we will define an abstract base class for association lists. + That base class will define methods + that can be shared by all subclasses + that represent an alist, + and it will declare abstract methods that need to be defined + differently within each subclass. +


Creative Commons License - - © Mitchell Wand, 2012-2015 + + © William D Clinger, 2017
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License. - -
- The work has been modified by William D Clinger in these ways - and more: - conversion from PowerPoint to HTML, and from Racket to Java. -
-
+ + +
+ + diff --git a/Inheritance/caseStudy1Objectives.html b/Inheritance/caseStudy1Objectives.html index c55d4a2..a977fc8 100644 --- a/Inheritance/caseStudy1Objectives.html +++ b/Inheritance/caseStudy1Objectives.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,42 +25,48 @@

Learning Objectives -

+

By the end of this lesson, you should be able to: -

+

  • - explain how inheritance lets us implement the - 25 methods listed in Java's - Map<K,V> interface by defining only one - of those methods -
  • + explain how an algebraic specification can specify + the purely functional operations of an abstract data type + without revealing the representation(s) of that data type + +
  • + respect the abstraction barrier presented by the public + interface that lists the operations of an abstract data type +
  • +
  • + design an implementation that may rely upon one or more + help methods that go beyond those listed by the public interface +
  • - identify inefficiencies that result from - excessive reliance on inheritance -
  • + reduce duplication of code by defining an abstract base class +
  • - design a better implementation - that improves efficiency by defining more methods - and using a better representation -
  • -
-
+ define a simple iterator method + + +
+ + diff --git a/Inheritance/caseStudy1Specification.html b/Inheritance/caseStudy1Specification.html new file mode 100644 index 0000000..742ccca --- /dev/null +++ b/Inheritance/caseStudy1Specification.html @@ -0,0 +1,89 @@ + + + + + + + + + + + + Algebraic Specification + + + + + + + + + + +
+

+ Algebraic Specification +

+
+

+ The abstract data type we are designing is immutable, + so we can use mathematical equations to specify + the behavior of its operations: +

+
+      // Specification of extend, lookup, and contains methods:
+      //
+      // Let a be an alist, and let k1 and k2 be unequal keys.  Then
+      //
+      //     a.extend(k1,v1).lookup(k1) = v1
+      //     a.extend(k1,v1).lookup(k2) = a.lookup(k2)
+      //
+      //     a.extend(k1,v1).contains(k1) = true
+      //     a.extend(k1,v1).contains(k2) = a.contains(k2)
+      //
+      // If empty_alist is a representation of an empty alist, then
+      //
+      //     empty_alist.contains(k1) = false
+
+

+ An equational specification such as the one given above + is called an + algebraic specification. +

+

+ Note that the algebraic specification given above + does NOT mention any specific constructor for an + empty association list. + We were careful to avoid mentioning any specific constructor + because different representations of alists may + need to pass different arguments to their constructors. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1Specification2.html b/Inheritance/caseStudy1Specification2.html new file mode 100644 index 0000000..5a9235e --- /dev/null +++ b/Inheritance/caseStudy1Specification2.html @@ -0,0 +1,89 @@ + + + + + + + + + + + + Determining the Set of Defined Keys + + + + + + + + + + +
+

+ Determining the Set of Defined Keys +

+
+

+ The operations specified so far would be enough for some + applications of finite functions, + but those operations do not give users any practical way + to learn which keys lie within the domain of a + particular finite function. +

+

+ We could define a keySet operation + that returns the set + of keys on which a finite function is defined, + and we could use an algebraic specification to specify that set: +

+
+      // If empty_alist is a representation of the empty alist, then
+      //     empty_alist.keySet() = { }
+      //
+      // If a is any alist, then
+      //     a.extend(k1,v1).keySet() = { k1 } ∪ a.keySet()
+
+

+ That keySet operation would work just fine, + and it ought to be perfectly straightforward to implement, + but it isn't as easy to implement as it should be because + Java's standard libraries offer very little support + for immutable sets (and other immutable data structures). + We'd have to design and implement an abstract data type + of immutable sets before we could return to designing our + abstract data type of immutable finite functions. +

+

+ To avoid that digression, we'll do something completely different. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1Specification3.html b/Inheritance/caseStudy1Specification3.html new file mode 100644 index 0000000..8cb5c1f --- /dev/null +++ b/Inheritance/caseStudy1Specification3.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + Specifying Mutable Objects + + + + + + + + + + +
+

+ Specifying Mutable Objects +

+
+

+ In place of the keySet operation + specified on the previous page, + we'll design and implement an iterator method + that returns a mutable Iterator<K> object + that can be used to generate the keys. +

+

+ The Iterator<K> object that will be + returned by our iterator method has mutable state, + so we can't specify the iterator method using the + straightforward kind of algebraic specification + we used to specify the + extend, + contains, and + lookup operations. + We'll have to specify the iterator method in words: +

+
+      // a.iterator() returns an Iterator<K> that generates the keys
+      // of a, in arbitrary order, without generating any key twice.
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1baseClass1.html b/Inheritance/caseStudy1baseClass1.html new file mode 100644 index 0000000..0eb01d3 --- /dev/null +++ b/Inheritance/caseStudy1baseClass1.html @@ -0,0 +1,109 @@ + + + + + + + + + + + + Abstract Base Class + + + + + + + + + + +
+

+ Abstract Base Class +

+
+

+ We are now ready to give an outline of our abstract base class. + The extend method will be the same for all subclasses, + so we might as well define it now. + All other methods are either abstract + or will be defined in the next few pages of this lesson; + the red dots show where the missing pieces will go. +

+
+      // The AListBase<K,V> class is an abstract base class that defines
+      // methods whose behavior will be the same for both empty and
+      // non-empty association lists.
+      
+      abstract class AListBase<K,V> implements MyAList<K,V> {
+      
+          // no fields in the base class, so its constructor
+          // takes no arguments and does nothing
+      
+          AListBase () { }
+      
+          // Returns an association list like this one
+          // except the given key is associated with the given value.
+      
+          public AListWithKeyIterator<K,V> extend (K key, V val) {
+              return new NonEmptyAList<K,V> (key, val, this);
+          }
+      
+          // Returns true iff the key is found within this AList.
+      
+          public abstract boolean contains (K key);
+      
+          // Returns the value associated with the given key.
+          // Throws a NoSuchElementException if the key is not found.
+      
+          public abstract V lookup (K key);
+      
+          // Returns an iterator that generates the keys of this
+          // association list, in arbitrary order, generating each
+          // key only once.
+      
+          public Iterator<K> iterator () { ... }
+      
+          // The equals(Object), hashCode(), and toString() methods go here.
+      
+          public boolean equals (Object o) { ... }
+          public int hashCode () { ... }
+          public String toString () { ... }
+      
+          // Help methods will go here.
+      
+          ...
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1baseClass2.html b/Inheritance/caseStudy1baseClass2.html new file mode 100644 index 0000000..5c9de2a --- /dev/null +++ b/Inheritance/caseStudy1baseClass2.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + Abstract Base Class, Continued + + + + + + + + + + +
+

+ Abstract Base Class, Continued +

+
+

+ Our abstract base class is now complete except for the + equals(Object), + hashCode(), and + toString() methods: +

+
+      // The AListBase<K,V> class is an abstract base class that defines
+      // methods whose behavior will be the same for both empty and
+      // non-empty association lists.
+      
+      abstract class AListBase<K,V> implements MyAList<K,V> {
+      
+          // no fields in the base class, so its constructor
+          // takes no arguments and does nothing
+      
+          AListBase () { }
+      
+          // Returns an association list like this one
+          // except the given key is associated with the given value.
+      
+          public AListWithKeyIterator<K,V> extend (K key, V val) {
+              return new NonEmptyAList<K,V> (key, val, this);
+          }
+      
+          // Returns true iff the key is found within this AList.
+      
+          public abstract boolean contains (K key);
+      
+          // Returns the value associated with the given key.
+          // Throws a NoSuchElementException if the key is not found.
+      
+          public abstract V lookup (K key);
+      
+          // Returns an iterator that generates the keys of this
+          // association list, in arbitrary order, generating each
+          // key only once.
+      
+          public Iterator<K> iterator () {
+              Set<K> keys = new HashSet<K>();
+              this.addKeys(keys);
+              keys = Collections.unmodifiableSet (keys);
+              return keys.iterator();
+          }
+      
+          public boolean equals (Object o) { ... }
+          public int hashCode () { ... }
+          public String toString () { ... }
+      
+          // Help method, not to be called from outside this file.
+      
+          public abstract void addKeys(Set<K> keys);
+      }
+
+

+ We haven't yet written the code that will prevent the + addKeys method from being called outside + this file. To remind ourselves to do that, however, + we've already written a comment that documents that + aspect of our intended design. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1baseClass3.html b/Inheritance/caseStudy1baseClass3.html new file mode 100644 index 0000000..9f1705d --- /dev/null +++ b/Inheritance/caseStudy1baseClass3.html @@ -0,0 +1,116 @@ + + + + + + + + + + + + equals(Object) + + + + + + + + + + +
+

+ equals(Object) +

+
+

+ The + equals(Object) + method is usually the most complicated of the three methods + we need to override so an inappropriate version won't be + inherited from the Object class. +

+

+ The most interesting part of the definition below is the fact + that we need to examine all of the keys in both this alist and in + the otherAList before we can tell whether the two + alists are equal. + The iterator method listed within the + AListWithKeyIterator<K,V> + interface lets us do that. + Because that interface extends the + Iterable interface, + we can write for loops + that will be compiled into code that + uses the iterators as necessary to generate all of the keys, + as in the definition below. + That simplifies the code and makes it easier to read. +

+
+

+ For historical reasons, the Java compiler is unable to + generate code that can check whether casts to a parameterized + type are compatible with the type parameters. + To prevent the Java compiler from complaining about its + inability to check that cast, we use an annotation that + asks the compiler not to complain about that kind of thing + inside the method we're defining. +

+
+
+      // Two association lists are considered equal if they
+      // contain the same keys and associate the same values
+      // with those keys.
+      
+      @SuppressWarnings("unchecked")
+      public boolean equals (Object o) {
+          if (o instanceof AListWithKeyIterator) {
+              AListWithKeyIterator<K,V> otherAList
+                  = (AListWithKeyIterator<K,V>) o;
+              for (K key : otherAList) {
+                  if (! (this.contains (key)))
+                      return false;
+              }
+              for (K key : this) {
+                  if (! (otherAList.contains (key)))
+                      return false;
+                  if (! (otherAList.lookup (key).equals (this.lookup (key))))
+                      return false;
+              }
+              return true;
+          }
+          else
+              return false;
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1baseClass4.html b/Inheritance/caseStudy1baseClass4.html new file mode 100644 index 0000000..c2afeae --- /dev/null +++ b/Inheritance/caseStudy1baseClass4.html @@ -0,0 +1,85 @@ + + + + + + + + + + + + hashCode() + + + + + + + + + + +
+

+ hashCode() +

+
+

+ The hashCode() method must be consistent with + the equals(Object) method. + Since the equals(Object) method doesn't pay + any attention to the order in which keys are generated by + an alist's iterator, the result returned by + hashCode() must also be independent of that order. +

+
+      public int hashCode () {
+          int result = 99;
+          for (K key : this) {
+              result = result +
+                  key.hashCode() -
+                  this.lookup (key).hashCode();
+          }
+          return result;
+      }
+
+
+

+ We could probably improve upon that definition, + but we'd have to be careful not to make the definition + incompatible with the equals method + or to violate the specification of hashCode() + in other ways. + It's easy to make mistakes here. +

+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1baseClass5.html b/Inheritance/caseStudy1baseClass5.html new file mode 100644 index 0000000..0e3aa9e --- /dev/null +++ b/Inheritance/caseStudy1baseClass5.html @@ -0,0 +1,85 @@ + + + + + + + + + + + + toString() + + + + + + + + + + +
+

+ toString() +

+
+

+ The toString() method doesn't have to be + consistent with the equals method, but + it's usually a good idea to make those methods consistent. + Otherwise users might be confused when two equal objects + print differently. +

+

+ Keeping toString() consistent with + equals greatly constrains the result + of the toString() method. + The equals method ignores the order + in which keys are generated by an alist's iterator, + so the string must also be independent of that order. +

+

+ That implies the string generally can't reveal any of + the keys or their associated values, because there's no + canonical order in which to show those keys or values. +

+

+ That's why the following definition reveals nothing more + about this alist than its hash code. +

+
+      public String toString () {
+          return "AList" + this.hashCode();
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1complete1.html b/Inheritance/caseStudy1complete1.html new file mode 100644 index 0000000..3d5c40b --- /dev/null +++ b/Inheritance/caseStudy1complete1.html @@ -0,0 +1,158 @@ + + + + + + + + + + + + Putting It All Together + + + + + + + + + + +
+

+ Putting It All Together +

+
+

+ All we have to do now is to put it all together. +

+

+ Here we get cute by putting almost everything you've seen + into a single class: +

+
    +
  • + the static factory method +
  • +
  • + the main method +
  • +
  • + the implementation-specific interface, + MyAList<K,V> +
  • +
  • + the abstract base class, AListBase<K,V> +
  • +
  • + the EmptyAList<K,V> class +
  • +
  • + the NonEmptyAList<K,V> class +
  • +
+

+ Making the last four of those things into + private static members of the ALists class + makes those four things completely inaccessible outside + of our implementation. +

+
+      // This class defines a static factory method that returns an empty
+      // AListWithKeyIterator<K,V>,
+      // and defines a main method for testing the association lists
+      // implemented within this file.
+      
+      import java.util.Iterator;
+      import java.util.NoSuchElementException;
+      import java.util.Set;
+      import java.util.HashSet;
+      import java.util.Collections;
+      
+      class ALists {
+      
+          private static AListWithKeyIterator theEmptyAList = new EmptyAList();
+      
+          // static factory method for creating an empty AListWithKeyIterator<K,V>
+      
+          @SuppressWarnings("unchecked")
+          public static <K,V> AListWithKeyIterator<K,V> empty () {
+              return (AListWithKeyIterator<K,V>) theEmptyAList;
+          }
+      
+          public static void main (String[] args) {
+              Tests.main (args);
+          }
+      
+          // To implement the iterator method, we'll need a help method.
+          // To call that help method with a receiver alist, we'll need to
+          // know alist defines that help method.
+          // That means the type of alist will need to be a type that
+          // is specific enough to guarantee alist defines that help method.
+          // To stay within the course's coding standards, we'll have to
+          // define an interface type that lists the help method.
+          // To prevent that help method and the interface that lists it
+          // from being used outside of the code in this class, we'll
+          // declare the interface as a private static member of the class.
+      
+          private static interface MyAList<K,V> extends AListWithKeyIterator<K,V> {
+      
+              // Given a mutable set, adds each key of this association list
+              // to the mutable set, without adding any key twice.
+      
+              void addKeys (Set<K> keys);
+          }
+      
+          // The AListBase<K,V> class is an abstract base class that defines
+          // methods whose behavior will be the same for both empty and
+          // non-empty association lists.
+      
+          private static abstract class AListBase<K,V> implements MyAList<K,V> { ... }
+      
+          // An object of class EmptyAlist<K,V> represents an empty partial map
+          // from K to V, that is, a map with an empty domain.
+      
+          private static class EmptyAList<K,V>
+              extends AListBase<K,V> 
+              implements MyAList<K,V> { ... }
+      
+          // The object constructed by new NonEmptyAList(k,v,rest) represents an
+          // association list just like 'rest', except that the key k is mapped
+          // to the value v.  Any other key is mapped to the value it had in 'rest'.
+      
+          private static class NonEmptyAList<K,V>
+              extends AListBase<K,V> 
+              implements MyAList<K,V> { ... }
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1dataDesign1.html b/Inheritance/caseStudy1dataDesign1.html new file mode 100644 index 0000000..09b040a --- /dev/null +++ b/Inheritance/caseStudy1dataDesign1.html @@ -0,0 +1,132 @@ + + + + + + + + + + + + Data Design + + + + + + + + + + +
+

+ Data Design +

+
+

+ There may be many different implementations of the + AListWithKeyIterator<K,V> + interface. +

+

+ The implementation we're describing uses this data design: +

+
+

+ A MyAList<K,V> is either +

+
    +
  • + an object of the EmptyAList<K,V> class, or +
  • +
  • + an object of the NonEmptyAList<K,V> class + that contains the following three fields: +
      +
    • + a key +
    • +
    • + the value associated with that key +
    • +
    • + a MyAList<K,V> + that represents the rest of this association list +
    • +
    +
  • +
+
+

+ The coding standards for this course require all variables + to be of some interface type. + We will define + MyAList<K,V> + as an interface so it can serve as the type for those variables. +

+

+ The MyAList<K,V> interface will extend + the AListWithKeyIterator<K,V> interface, + so any variable of type + MyAList<K,V> + can be used as though it were of type + AListWithKeyIterator<K,V>. + In particular, the value of a variable of type + MyAList<K,V> + will be an object that responds to all of the messages + that can be sent to an object that supports the methods + listed in the + AListWithKeyIterator<K,V> interface. +

+

+ If we discover that we need some additional help methods, + we can add those methods to the + MyAList<K,V> + interface without changing the + AListWithKeyIterator<K,V> interface. +

+
+      interface MyAList<K,V> extends AListWithKeyIterator<K,V> {
+      
+          // Any help methods we need will be listed here.
+      }
+
+

+ That MyAList<K,V> interface is part of our + design, and is not intended to be used by any other code. + We will make that interface inaccessible outside of our + implementation, so the only classes that implement the + MyAList<K,V> interface will be the + classes we define ourselves. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1emptyAList1.html b/Inheritance/caseStudy1emptyAList1.html new file mode 100644 index 0000000..181a791 --- /dev/null +++ b/Inheritance/caseStudy1emptyAList1.html @@ -0,0 +1,99 @@ + + + + + + + + + + + + The EmptyAList Class + + + + + + + + + + +
+

+ The EmptyAList Class +

+
+

+ That completes our definition of the abstract base class. +

+

+ We will now go on to define the + EmptyAList and + NonEmptyAList classes. +

+

+ The EmptyAList class is pretty simple, + because all of the hard work was done in the + abstract base class. +

+
+      // An object of class EmptyAlist<K,V> represents an empty partial map
+      // from K to V, that is, a map with an empty domain.
+      
+      class EmptyAList<K,V>
+          extends AListBase<K,V> 
+          implements MyAList<K,V> {
+      
+          // Returns true iff the key is found within this AList.
+      
+          public boolean contains (K key) {
+              return false;
+          }
+      
+          // Returns the value associated with the given key.
+          // Throws a NoSuchElementException if the key is not found.
+      
+          public V lookup (K key) {
+              throw new NoSuchElementException ("key not found: " + key);
+          }
+      
+          // Help method, not to be called from outside this file.
+          // Given a mutable set, adds each key of this association list
+          // to the mutable set, without adding any key twice.
+      
+          public void addKeys (Set<K> keys) { }
+      
+          // All other methods are defined by the base class.
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1interface.html b/Inheritance/caseStudy1interface.html new file mode 100644 index 0000000..f101a17 --- /dev/null +++ b/Inheritance/caseStudy1interface.html @@ -0,0 +1,119 @@ + + + + + + + + + + + + The AListWithKeyIterator<K> Interface + + + + + + + + + + +
+

+ The AListWithKeyIterator Interface +

+
+

+ Because our association lists will support an + iterator + method that generates the keys of this association list, + we'll use + AListWithKeyIterator<K,V> + as the name of our abstract data type. +

+

+ Instead of adding an iterator() method to + the interface's list of methods, we'll accomplish much + the same thing by defining the interface below so it + extends the pre-defined Iterable<K> + interface, which already lists an iterator() + method. + Extending the pre-defined Iterable<K> + interface is better than just listing an iterator() + method because it will allow users of our + AListWithKeyIterator<K,V> + type to write for-each loops that loop over the keys. + (We'll rely + on such loops when we write an + equals(Object) method.) +

+

+ The interface for that ADT is: +

+
+      // An AListWithKeyIterator<K,V> is an object of any class that implements
+      // the AListWithKeyIterator<K.V> interface.
+      
+      // Interpretation:
+      // An AlistWithKeyIterator<K,V>
+      //     represents a finite partial map from K to V
+      
+      // Specification of extend, lookup, and contains methods:
+      //
+      //     ...
+      
+      // The AListWithKeyIterator<K,V> interface extends
+      // the Iterable<K> interface, which lists an iterator() method,
+      // so we have to specify the behavior of that method as well:
+      //
+      //     a.iterator() returns an Iterator<K> that generates the keys
+      //     of a, in arbitrary order, without generating any key twice.
+      
+      interface AListWithKeyIterator<K,V> extends Iterable<K> {
+      
+          // Returns an association list like this one
+          // except the given key is associated with the given value.
+      
+          AListWithKeyIterator<K,V> extend (K key, V val);
+      
+          // Returns true iff the key is found within this AList.
+      
+          boolean contains (K key);
+      
+          // Returns the value associated with the given key.
+          // Throws a NoSuchElementException if the key is not found.
+      
+          V lookup (K key);
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1iteratorMethod1.html b/Inheritance/caseStudy1iteratorMethod1.html new file mode 100644 index 0000000..ba084d9 --- /dev/null +++ b/Inheritance/caseStudy1iteratorMethod1.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + Writing an Iterator Method + + + + + + + + + + +
+

+ Writing an Iterator Method +

+
+

+ The most interesting of the missing pieces is the + iterator method. +

+

+ As you may recall, we decided to define + an iterator method because + Java's standard libraries have such poor support + for immutable sets. + If not for that, we'd just define a keySet + method that returns an immutable set of this alist's keys. +

+

+ Java does give us pre-defined classes for creating + and modifying mutable sets. + Furthermore, Java gives us a way to convert a mutable set + into an immutable set whenever we want. + So we could go back and reconsider our earlier decision + to define an iterator method instead of + a keySet method. +

+

+ We're going to stick with our decision to define an + iterator method. + That will give us a chance to write code that creates + and manipulates mutable objects. + Besides, every Java programmer should know how to write + an iterator method, + so we need the practice. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1iteratorMethod2.html b/Inheritance/caseStudy1iteratorMethod2.html new file mode 100644 index 0000000..aea34a2 --- /dev/null +++ b/Inheritance/caseStudy1iteratorMethod2.html @@ -0,0 +1,142 @@ + + + + + + + + + + + + Writing an Iterator Method + + + + + + + + + + +
+

+ Writing an Iterator Method +

+
+

+ To write our + iterator method, + we will use the following strategy: +

+
    +
  1. + Create a mutable Set, named keys. + That set starts out as an empty set. +
  2. +
  3. + Use a help method to add all of the keys found within this alist. +
  4. +
  5. + After all keys have been added to the set, make it immutable. +
  6. +
  7. + Use the set's own iterator method to create + an Iterator<K> that generates the keys + in arbitrary order. +
  8. +
  9. + Return that Iterator<K>. +
  10. +
+
+

+ We could of course write our iterator method + entirely from scratch, but that is seldom necessary. + Using a pre-defined class to implement iterators, as + in the strategy outlined above, is a standard idiom in + Java. It is simpler, less error-prone, and easier to + understand than writing an iterator method + from scratch. +

+
+

+ Here, then, is the definition of our iterator method: +

+
+      // Returns an iterator that generates the keys of this
+      // association list, in arbitrary order, generating each
+      // key only once.
+      
+      public Iterator<K> iterator () {
+          Set<K> keys = new HashSet<K>();
+          this.addKeys(keys);
+          keys = Collections.unmodifiableSet (keys);
+          return keys.iterator();
+      }
+
+
+

+ We can't use a TreeSet here because there + might not be any total ordering defined on the keys, + but it's okay to use a HashSet because + every Java object has a hashCode() method + that's compatible with equals(Object). +

+
+

+ We'll have to define addKeys as a help method. + To make sure all of the alists we're implementing support + that help method, we'll list it in the + MyAList<K,V> interface: +

+
+      interface MyAList<K,V> extends AListWithKeyIterator<K,V> {
+      
+          // Given a mutable set, adds each key of this association list
+          // to the mutable set, without adding any key twice.
+      
+          void addKeys (Set<K> keys);
+      }
+
+
+

+ Remember: All methods of + AListWithKeyIterator<K,V> + are inherited by MyAList<K,V>. +

+
+

+ We will also declare that help method as an abstract method + inside our base class. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1nonEmptyAList1.html b/Inheritance/caseStudy1nonEmptyAList1.html new file mode 100644 index 0000000..bb7e167 --- /dev/null +++ b/Inheritance/caseStudy1nonEmptyAList1.html @@ -0,0 +1,84 @@ + + + + + + + + + + + + The NonEmptyAList Class + + + + + + + + + + +
+

+ The NonEmptyAList Class +

+
+

+ The NonEmptyAList class isn't very complicated + either, but we'll look at it in three pieces. + First, we'll look at the fields and the Java constructor + that initializes those fields: +

+
+      // The object constructed by new NonEmptyAList(k,v,rest) represents an
+      // association list just like 'rest', except that the key k is mapped
+      // to the value v.  Any other key is mapped to the value it had in 'rest'.
+      
+      class NonEmptyAList<K,V>
+          extends AListBase<K,V> 
+          implements MyAList<K,V> {
+      
+          private K key;             // key for the first entry in this AList
+          private V val;             // val for the first entry in this AList
+          private MyAList<K,V> rest; // the other entries in this AList
+      
+          NonEmptyAList (K key, V val, MyAList<K,V> rest) {
+              this.key = key;
+              this.val = val;
+              this.rest = rest;
+          }
+      
+          ...
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1nonEmptyAList2.html b/Inheritance/caseStudy1nonEmptyAList2.html new file mode 100644 index 0000000..00dc832 --- /dev/null +++ b/Inheritance/caseStudy1nonEmptyAList2.html @@ -0,0 +1,97 @@ + + + + + + + + + + + + The NonEmptyAList Class + + + + + + + + + + +
+

+ The NonEmptyAList Class +

+
+

+ Next, we'll define the + contains and lookup methods: +

+
+      // The object constructed by new NonEmptyAList(k,v,rest) represents an
+      // association list just like 'rest', except that the key k is mapped
+      // to the value v.  Any other key is mapped to the value it had in 'rest'.
+      
+      private static class NonEmptyAList<K,V>
+          extends AListBase<K,V> 
+          implements MyAList<K,V> {
+      
+          private K key;             // key for the first entry in this AList
+          private V val;             // val for the first entry in this AList
+          private MyAList<K,V> rest; // the other entries in this AList
+      
+          NonEmptyAList (K key, V val, MyAList<K,V> rest) { ... }
+      
+          // Returns true iff the key is found within this AList.
+      
+          public boolean contains (K otherKey) {
+              if (otherKey.equals (this.key))
+                  return true;
+              else
+                  return rest.contains (otherKey);
+          }
+      
+          // Returns the value associated with the given key.
+          // Throws a NoSuchElementException if the key is not found.
+      
+          public V lookup (K key) {
+              if (key.equals (this.key))
+                  return this.val;
+              else
+                  return rest.lookup (key);
+          }
+      
+          ...
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1nonEmptyAList3.html b/Inheritance/caseStudy1nonEmptyAList3.html new file mode 100644 index 0000000..ac3dd97 --- /dev/null +++ b/Inheritance/caseStudy1nonEmptyAList3.html @@ -0,0 +1,89 @@ + + + + + + + + + + + + The NonEmptyAList Class + + + + + + + + + + +
+

+ The NonEmptyAList Class +

+
+

+ Finally, we'll define the + help method that's used by the + iterator method that's defined in the base class: +

+
+      // The object constructed by new NonEmptyAList(k,v,rest) represents an
+      // association list just like 'rest', except that the key k is mapped
+      // to the value v.  Any other key is mapped to the value it had in 'rest'.
+      
+      private static class NonEmptyAList<K,V>
+          extends AListBase<K,V> 
+          implements MyAList<K,V> {
+      
+          private K key;             // key for the first entry in this AList
+          private V val;             // val for the first entry in this AList
+          private MyAList<K,V> rest; // the other entries in this AList
+      
+          ...
+      
+          // Help method, not to be called from outside this file.
+          // Given a mutable set, adds each key of this association list
+          // to the mutable set, without adding any key twice.
+      
+          public void addKeys (Set<K> keys) {
+              if (! (keys.contains (this.key)))
+                  keys.add (this.key);
+              rest.addKeys (keys);
+          }
+      
+          // All other methods are defined by the base class.
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy1summary.html b/Inheritance/caseStudy1summary.html new file mode 100644 index 0000000..d14344f --- /dev/null +++ b/Inheritance/caseStudy1summary.html @@ -0,0 +1,88 @@ + + + + + + + + + + + + Summary + + + + + + + + + + +
+

+ Summary +

+
+
    +
  • + We wrote an algebraic specification for the purely + functional operations of our abstract data type. +
  • +
  • + We described the iterator method in words. +
  • +
  • + We defined an interface so users of our abstract data type + will know what methods are available. +
  • +
  • + We define another interface for our use only. + Our own private interface extends the public interface by + listing any help methods we might need. +
  • +
  • + We defined an abstract base class that implements our + private interface and defines methods that can be shared + by the various concrete subclasses we'll be defining. +
  • +
  • + We defined the concrete subclasses we needed to complete + our implementation of the abstract data type. +
  • +
  • + We packaged it all up so the code we wrote is the only + code that's allowed to use our private interface and + the classes that implement that private interface. +
  • +
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2.html b/Inheritance/caseStudy2.html index 385c1e8..3303cb0 100644 --- a/Inheritance/caseStudy2.html +++ b/Inheritance/caseStudy2.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,43 +25,80 @@

Case Study: Immutable Finite Functions, Part 2 -

+

- In this case study, we design a second implementation - of the IMap<K,V> data type defined in - the previous lesson. - That second implementation will use binary search trees - instead of linear search. -

-

- To reduce duplication of code, we define an abstract base class - from which all of our implementations of - IMap<K,V> can inherit. -

+ In this case study, we design and implement + an immutable abstract data type + of finite functions + that builds on our + AListWithKeyIterator<K,V> example + to define a class that will implement the entire + java.util.Map<K,V> interface. +

- To reduce duplication of code in our implementation of - binary search trees, we define a second abstract base class - from which the classes for empty and non-empty trees can inherit. -

+ The IMap<K,V> interface + we define in this lesson extends + java.util.Map<K,V>. +

- This case study will also provide many opportunities to - discuss Java-specific syntax, semantics, and APIs. -

-
+ Our first implementation of the IMap<K,V> + reuses our implementation of + AListWithKeyIterator<K,V> + from the previous lesson by + composing + its association lists with classes + that add many new methods, most of them inherited from an + abstract base class defined in Java's java.util package: + AbstractMap<K,V>. +

+
+

+ The Map<K,V> interface + includes some operations that have side effects. + Luckily for us, all of those side-effecting operations are + optional. + That means we can implement an ADT of immutable finite maps + by arranging for all of the side-effecting methods of the + Map<K,V> interface to throw an + UnsupportedOperationException + if those methods are ever called. +

+
+
+
+ + Creative Commons License + + © Mitchell Wand, 2012-2015 +
+ This work is licensed under a + + Creative Commons Attribution-NonCommercial 4.0 International + License. + +
+ The work has been modified by William D Clinger in these ways + and more: + conversion from PowerPoint to HTML, and from Racket to Java. +
+
+ + diff --git a/Inheritance/caseStudy2IMap.html b/Inheritance/caseStudy2IMap.html new file mode 100644 index 0000000..b20b8ec --- /dev/null +++ b/Inheritance/caseStudy2IMap.html @@ -0,0 +1,76 @@ + + + + + + + + + + + + The IMap Interface + + + + + + + + + + +
+

+ The IMap<K,V> Interface +

+
+
+      // An IMap<K,V> is an object of any class that implements IMap<K,V>.
+      //
+      // Interpretation: An IMap<K,V> represents an immutable finite function
+      // from keys to values.
+      //
+      // IMap<K,V> extends java.util.Map<K,V>, so an IMap<K,V> can be used
+      // as an unmodifiable Map<K,V>.
+      
+      import java.util.Map;
+      
+      interface IMap<K,V> extends Map<K,V> {
+      
+          // Returns an IMap like this one except the given key is associated
+          // with the given value.  The extend operation does not modify this
+          // IMap.
+      
+          IMap<K,V> extend (K key, V value);
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap11.html b/Inheritance/caseStudy2IMap11.html new file mode 100644 index 0000000..b7d6a02 --- /dev/null +++ b/Inheritance/caseStudy2IMap11.html @@ -0,0 +1,110 @@ + + + + + + + + + + + + Inefficiencies + + + + + + + + + + +
+

+ Inefficiencies +

+
+

+ The predefined AbstractMap<K,V> base class + made it a lot easier to implement an + Imap<K,V> interface that inherits all of the + methods listed in + Map<K,V>, but we paid a price in efficiency. +

+

+ All of the operations we inherit from + AbstractMap<K,V> are implemented in that + class by calling the abstract + entrySet method we defined in our + AListIMap<K,V> subclass. +

+

+ That means all of the inherited methods have to create and initialize + a new object of the HashMap class. + That takes Ω(n2) time, + where n is the number of key/value pairs in the IMap. +

+
+

+ We have to create an entry for each of the n key/value pairs, + and the average time to look up each value is + Θ(n) + because we're using association lists. +

+
+

+ We could make at least some of the inherited methods run + faster by overriding them in our AListIMap. +

+

+ We could, for example, implement the + contains and lookup methods + by forwarding to the corresponding methods of the + association list found in this.alist. + That would make those important methods run a lot faster. +

+

+ Implementing all of the other new methods from scratch + could be a lot of work. + If we're going to do that much work, we might as well try + to use a potentially more efficient representation + while we're at it. +

+

+ We could use binary search trees instead of association lists. + Better yet, we could use + red-black trees. + We'll leave that for a programming assignment, + or for your algorithms course. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap1a.html b/Inheritance/caseStudy2IMap1a.html new file mode 100644 index 0000000..c3f8f45 --- /dev/null +++ b/Inheritance/caseStudy2IMap1a.html @@ -0,0 +1,114 @@ + + + + + + + + + + + + The Composition Pattern + + + + + + + + + + +
+

+ The Composition Pattern +

+
+

+ To avoid having to start over from scratch, + we'll reuse our association lists from the + previous lesson by designing a class that + implements the IMap<K,V> interface + using a field that represents + the finite function as one of those association lists. + The + extend, + contains, and + lookup + methods will be implemented by + forwarding + their message to the association list. +

+

+ The general idea is to define a class that looks something like this: +

+
+      class AListIMap<K,V> implements IMap<K,V> {
+      
+          AListWithKeyIterator<K,V> alist;    // association list of key/value pairs
+      
+          // Java constructors
+      
+          AListIMap (AListWithKeyIterator<K,V> alist) {
+              this.alist = alist;
+          }
+      
+          // public methods listed by IMap<K,V> interface
+      
+          // Returns an IMap like this one except the given key is associated
+          // with the given value.  The extend operation does not modify this
+          // IMap.
+      
+          public IMap<K,V> extend (K key, V value) {
+              return new AListIMap<K,V> (alist.extend (key, value));
+          }
+      
+          // Returns true iff the key is found within this AList.
+      
+          public boolean contains (K key) {
+              return alist.contains (key);
+          }
+      
+          // Returns the value associated with the given key.
+          // Throws a NoSuchElementException if the key is not found.
+      
+          public V lookup (K key) {
+              return alist.lookup (key);
+          }
+      
+          // The other methods will be added here.
+      
+          ...
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap2.html b/Inheritance/caseStudy2IMap2.html new file mode 100644 index 0000000..338aac0 --- /dev/null +++ b/Inheritance/caseStudy2IMap2.html @@ -0,0 +1,103 @@ + + + + + + + + + + + + The IMap Interface + + + + + + + + + + +
+

+ The IMap<K,V> Interface +

+
+

+ That looks pretty simple, but the IMap<K,V> interface + inherits 25 methods listed by the + Map<K,V> interface: +

+
+      void                clear()
+      default V           compute(K, BiFunction<? super K,? super V,? extends V>)
+      default V           computeIfAbsent(K, BiFunction<? super K,? super V,? extends V>)
+      default V           computeIfPresent(K, BiFunction<? super K,? super V,? extends V>)
+      boolean             containsKey(Object);
+      boolean             containsValue(Object);
+      Set<Map.Entry<K,V>> entrySet()
+      boolean             equals(Object)
+      default void        forEach(BiConsumer<? super K,? super V>)
+      V                   get(Object)
+      default V           getOrDefault(Object, V)
+      int                 hashCode()
+      boolean             isEmpty()
+      Set<K>              keySet()
+      default V           merge(K, V, BiFunction<? super V,? super V,? extends V>)
+      V                   put(K, V)
+      void                putAll(Map<? extends K,? extends V>)
+      default V           putIfAbsent(K, V)
+      V                   remove(Object)
+      default boolean     remove(Object,Object)
+      default V           replace(K, V)
+      default boolean     replace(K, V, V)
+      default void        replaceAll(BiFunction<? super K,? super V,? extends V>)
+      int                 size()
+      Collection<V>       values()
+
+

+ Optional methods are shown in light blue. + (The Java 8 API documentation is less than clear on which methods + are optional, but I believe the methods shown in blue are allowed + to throw an UnsupportedOperationException.) +

+

+ Implementing all of those methods could be a lot of work. +

+

+ To avoid most of that work, we will implement + IMap<K,V> by extending the + AbstractMap<K,V> class that is predefined + in the java.util package. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap3.html b/Inheritance/caseStudy2IMap3.html new file mode 100644 index 0000000..807012d --- /dev/null +++ b/Inheritance/caseStudy2IMap3.html @@ -0,0 +1,88 @@ + + + + + + + + + + + + First Implementation of IMap<K,V> + + + + + + + + + + +
+

+ First Implementation of IMap<K,V> +

+
+

+ Fortunately, we can rely on inheritance to do most of the work + for us. All we have to do is to extend a predefined abstract + base class named + java.util.AbstractMap: +

+
+      // Constructor templates for AListIMap<K,V>:
+      //     new AListIMap<K,V> (AListWithKeyIterator<K,V> alist)
+      //     new AListIMap<K,V> ()
+      // Interpretation:
+      //     alist is an association list of key/value pairs
+      //     if alist is omitted, creates an empty map
+      
+      import java.util.Map;
+      import java.util.AbstractMap;
+      ...
+      
+      // Strategy, quoted from the documentation for AbstractMap:
+      //
+      // To implement an unmodifiable map, the programmer needs only to
+      // extend [the AbstractMap] class and provide an implementation
+      // for the entrySet method, which returns a set-view of the map's
+      // mappings.  Typically, the returned set will, in turn, be
+      // implemented atop AbstractSet.  This set should not support the
+      // add or remove methods, and its iterator should not support the
+      // remove method.
+      
+      class AListIMap<K,V> extends AbstractMap<K,V> implements IMap<K,V> {
+          ...
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap4.html b/Inheritance/caseStudy2IMap4.html new file mode 100644 index 0000000..1b751c8 --- /dev/null +++ b/Inheritance/caseStudy2IMap4.html @@ -0,0 +1,113 @@ + + + + + + + + + + + + First Implementation of IMap<K,V> + + + + + + + + + + +
+

+ First Implementation of IMap<K,V> +

+
+

+ We have to do three things: +

+
    +
  • + define the fields and Java constructors +
  • +
  • + define the extends method of + the IMap interface. +
  • +
  • + define the entrySet abstract method + that's declared in AbstractMap. +
  • +
+

+ That's all we have to do: +

+
+      class AListIMap<K,V> extends AbstractMap<K,V> implements IMap<K,V> {
+      
+          AListWithKeyIterator<K,V> alist;    // association list of key/value pairs
+      
+          // Java constructors
+      
+          AListIMap () {
+              this.alist = ALists.empty();
+          }
+      
+          AListIMap (AListWithKeyIterator<K,V> alist) {
+              this.alist = alist;
+          }
+      
+          // public methods listed by IMap<K,V> interface
+      
+          // Returns an IMap like this one except the given key is associated
+          // with the given value.  The extend operation does not modify this
+          // IMap.
+      
+          public IMap<K,V> extend (K key, V value) {
+              ...
+          }
+      
+          // public methods listed by Map<K,V> interface
+      
+          // Returns a set of the key/value pairs in this Map.
+          // Instead of implementing that set atop AbstractSet,
+          // we use an unmodifiable HashSet.
+      
+          public Set<Map.Entry<K,V>> entrySet () {
+              ...
+          }
+      
+          // all other public methods are defined by AbstractMap<K,V>
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap5.html b/Inheritance/caseStudy2IMap5.html new file mode 100644 index 0000000..edaf337 --- /dev/null +++ b/Inheritance/caseStudy2IMap5.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + First Implementation of IMap<K,V> + + + + + + + + + + +
+

+ First Implementation of IMap<K,V> +

+
+

+ To define the extend method, we forward to + the extend method of our + AListWithKeyIterator ADT: +

+
+      class AListIMap<K,V> extends AbstractMap<K,V> implements IMap<K,V> {
+      
+          AListWithKeyIterator<K,V> alist;    // association list of key/value pairs
+      
+          ...
+      
+          // Returns an IMap like this one except the given key is associated
+          // with the given value.  The extend operation does not modify this
+          // IMap.
+      
+          public IMap<K,V> extend (K key, V value) {
+              return new AListIMap<K,V> (alist.extend (key, value));
+          }
+      
+          ...
+      }
+
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap6.html b/Inheritance/caseStudy2IMap6.html new file mode 100644 index 0000000..f7d0195 --- /dev/null +++ b/Inheritance/caseStudy2IMap6.html @@ -0,0 +1,109 @@ + + + + + + + + + + + + First Implementation of IMap<K,V> + + + + + + + + + + +
+

+ First Implementation of IMap<K,V> +

+
+

+ To define the entrySet method, + we'll use a HashSet: +

+
+      import java.util.Map;
+      import java.util.Map.Entry;
+      import java.util.AbstractMap;
+      import java.util.AbstractMap.SimpleImmutableEntry;
+      
+      import java.util.Set;
+      import java.util.HashSet;
+      import java.util.Collections;
+      
+      class AListIMap<K,V> extends AbstractMap<K,V> implements IMap<K,V> {
+      
+          AListWithKeyIterator<K,V> alist;    // association list of key/value pairs
+      
+          ...
+      
+          // Returns a set of the key/value pairs in this Map.
+      
+          public Set<Map.Entry<K,V>> entrySet () {
+              Set<Map.Entry<K,V>> entries = new HashSet<Map.Entry<K,V>>();
+              for (K key : alist) {
+                  V value = alist.lookup (key);
+                  entries.add (new SimpleImmutableEntry<K,V> (key, value));
+              }
+              return Collections.unmodifiableSet (entries);
+          }
+      
+          ...
+      }
+
+

+ Each element of the entries set will be a + Map.Entry<K,V> + that represents a key/value pair. + The for loop goes through all the keys + of this AListIMap, looking up the + value associated with the key and creating a new + SimpleImmutableEntry + for that key and value, + which it then adds to the set of entries. +

+

+ We could just return that set of entries as a mutable set, + but that would allow users to mutate that set, and some users + might do so without realizing their side effects do not change + the underlying IMap. + To reduce confusion, we return an unmodifiable version + of the set. +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMap7.html b/Inheritance/caseStudy2IMap7.html new file mode 100644 index 0000000..a2c8d05 --- /dev/null +++ b/Inheritance/caseStudy2IMap7.html @@ -0,0 +1,106 @@ + + + + + + + + + + + + First Implementation of IMap<K,V> + + + + + + + + + + +
+

+ First Implementation of IMap<K,V> +

+
+

+ That completes our first implementation of + IMap<K,V>. +

+
+      class AListIMap<K,V> extends AbstractMap<K,V> implements IMap<K,V> {
+      
+          AListWithKeyIterator<K,V> alist;    // association list of key/value pairs
+      
+          // Java constructors
+      
+          AListIMap () {
+              this.alist = ALists.empty();
+          }
+      
+          AListIMap (AListWithKeyIterator<K,V> alist) {
+              this.alist = alist;
+          }
+      
+          // public methods listed by IMap<K,V> interface
+      
+          // Returns an IMap like this one except the given key is associated
+          // with the given value.  The extend operation does not modify this
+          // IMap.
+      
+          public IMap<K,V> extend (K key, V value) {
+              return new AListIMap<K,V> (alist.extend (key, value));
+          }
+      
+          // public methods listed by Map<K,V> interface
+      
+          // Returns a set of the key/value pairs in this Map.
+          // Instead of implementing that set atop AbstractSet,
+          // we use an unmodifiable HashSet.
+      
+          public Set<Map.Entry<K,V>> entrySet () {
+              Set<Map.Entry<K,V>> entries = new HashSet<Map.Entry<K,V>>();
+              for (K key : alist) {
+                  V value = alist.lookup (key);
+                  entries.add (new SimpleImmutableEntry<K,V> (key, value));
+              }
+              return Collections.unmodifiableSet (entries);
+          }
+      
+          // all other public methods are defined by AbstractMap<K,V>
+      }
+
+

+ (We wrote the tests first, of course.) +

+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2IMapSummary.html b/Inheritance/caseStudy2IMapSummary.html new file mode 100644 index 0000000..70ce000 --- /dev/null +++ b/Inheritance/caseStudy2IMapSummary.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + Summary + + + + + + + + + + +
+

+ Summary +

+
+
    +
  • + Our implementation of IMap<K,V> + was made easier because we reused our association lists + via composition. +
  • +
  • + Our implementation + was made even easier by inheriting 24 methods from a + predefined abstract base class. +
  • +
  • + We didn't even have to understand what those inherited + methods are supposed to do. +
  • +
  • + The generality of the methods inherited from the abstract + base class may create some inefficiencies. +
  • +
  • + If we want a more efficient implementation, we will + probably have to use a more sophisticated representation + and override some of the methods we inherit from the + abstract base class. +
  • +
+
+
+ + + + + + + + diff --git a/Inheritance/caseStudy2Objectives.html b/Inheritance/caseStudy2Objectives.html index 4ca307e..8705f0b 100644 --- a/Inheritance/caseStudy2Objectives.html +++ b/Inheritance/caseStudy2Objectives.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,69 +25,48 @@

Learning Objectives -

+

- By the end of this long lesson, you should be able to: -

+ By the end of this lesson, you should be able to: +

  • - give examples and explain how inheritance makes it - easier to implement abstract data types -
  • -
  • - give examples of interfaces that extend other interfaces -
  • -
  • - give examples of both static and dynamic factory methods -
  • -
  • - explain how immutable binary search trees are searched or extended -
  • -
  • - write more sophisticated equals and hashCode - methods -
  • -
  • - import classes from java.util -
  • + explain how composition enables reuse + even without inheritance +
  • - create iterators by copying the data to be generated into - a predefined Collection and using that - Collection's iterator -
  • + explain how inheritance lets us implement the + 25 methods listed in Java's + Map<K,V> interface by defining only one + of those methods +
  • - explain why Java is considered a single-inheritance language -
  • + identify inefficiencies that result from + excessive reliance on inheritance +
  • - suppress warning messages about casts involving type parameters - that Java is unable to check at run time -
  • -
  • - rank Java's four access modifiers (including the default) - in order of increasing access or in order of increasing protection -
  • -
  • - use Java's access modifiers appropriately -
  • -
  • - use Java's final keyword to prevent subclassing -
  • -
-
+ design a better implementation + that improves efficiency by defining more methods + and using a better representation + + +
+ + diff --git a/Inheritance/inheritance1.html b/Inheritance/inheritance1.html index 66d9824..64fc5e3 100644 --- a/Inheritance/inheritance1.html +++ b/Inheritance/inheritance1.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,47 +25,49 @@

Basics of Inheritance -

+

Inheritance is a technique for generalizing over common parts of class definitions. -

+

When we create such a generalization, we specialize by subclassing. -

+

Languages with inheritance introduce many new design choices, as well as some pitfalls. -

+


Creative Commons License - + © Mitchell Wand, 2012-2015
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License. - +
The work has been modified by William D Clinger in these ways and more: conversion from PowerPoint to HTML, and from Racket to Java. -
-
+ +
+ + diff --git a/Inheritance/inheritanceBasicsSummary.html b/Inheritance/inheritanceBasicsSummary.html index 40032da..e952e0f 100644 --- a/Inheritance/inheritanceBasicsSummary.html +++ b/Inheritance/inheritanceBasicsSummary.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,43 +25,45 @@

Summary -

+
  • Objects find methods by searching up the inheritance chain. -
  • +
  • That search is faster than you might think. -
  • +
  • Java constructors always invoke a constructor for the superclass. If you don't write that explicitly, using super(...), the Java compiler will write super() for you. -
  • +
  • Fields and methods of a Java superclass can be accessed using super.h and super.f(...) syntaxes. -
  • +
  • Writing @Override when overriding a Java method is considered good practice. -
  • -
-
+ + +
+ + diff --git a/Inheritance/inheritanceDefaults1.html b/Inheritance/inheritanceDefaults1.html index c26a51a..ee9d9f5 100644 --- a/Inheritance/inheritanceDefaults1.html +++ b/Inheritance/inheritanceDefaults1.html @@ -9,12 +9,12 @@ - The Overriding-Defaults Pattern + Overriding Default Methods + href="../cs5010.css" /> @@ -24,37 +24,38 @@

- The Overriding-Defaults Pattern -

+ Overriding Default Methods +

Defining UTC2 as a subclass of UTC1 - is an example of the overriding-defaults pattern. - In that pattern: -

+ is an example of a common pattern in which: +

  • The superclass has a complete set of behaviors. -
  • +
  • The subclass makes some incremental change in those behaviors by overriding some of them. -
  • -
-
+ + +
+ + diff --git a/Inheritance/inheritanceExample1.html b/Inheritance/inheritanceExample1.html index cf5532d..b886f3c 100644 --- a/Inheritance/inheritanceExample1.html +++ b/Inheritance/inheritanceExample1.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,75 +25,75 @@

Example: UTC2 -

+

Sometimes we want to define a new class that is just a small variation of an old class. -

+

Suppose, for example, we want to define a class UTC2 that represents a UTC value using the hour as defined by Eastern Standard Time. -

+

We have already done that in the UTC2 class defined within a - - previous lesson. - + previous + lesson. If you compare the definition of UTC2 against the - - definition of UTC1, - + definition + of UTC1, you will see these differences: -

+

  • the interpretation of field h is different -
  • +
  • the Java constructor is different -
  • +
  • the hour method is different -
  • +
  • the main method (for unit testing) is different -
  • -
+ +

Everything else is the same: -

+

  • the field names and types are the same -
  • +
  • except for hour and main, all of the methods are the same -
  • -
+ +

It seems silly to duplicate so much code for such a minor change of representation. Inheritance can save us from writing exactly the same code in two different classes. -

-
+

+
+ + diff --git a/Inheritance/inheritanceExample2.html b/Inheritance/inheritanceExample2.html index 5e903cc..3b86469 100644 --- a/Inheritance/inheritanceExample2.html +++ b/Inheritance/inheritanceExample2.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,25 +25,25 @@

Subclass: UTC2 -

+

Here is the new definition of UTC2. -

+

The extends UTC1 declares UTC1 to be the superclass, so all of the fields and methods defined in UTC1 will be inherited by UTC2. -

+

There might be some methods in UTC1 that rely on the h field being the UTC hour rather than the EST hour. We don't want to break those methods, so we define our own h field in UTC2. -

+

The call to super inside the Java constructor @@ -52,7 +52,7 @@

of the superclass. The assignment to this.h then initializes the h field of UTC2. -

+

       // Constructor template for UTC2:
       //     new UTC2 (h, m)
@@ -98,21 +98,23 @@ 

UTC2tests.main(args); } } -

-

+ +
+ + diff --git a/Inheritance/inheritanceHow1.html b/Inheritance/inheritanceHow1.html index aa83c50..36a8c0b 100644 --- a/Inheritance/inheritanceHow1.html +++ b/Inheritance/inheritanceHow1.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,44 +25,46 @@

How Inheritance Works -

+

A dynamic method call x.f(...) causes the object x to search its inheritance chain for a suitable definition of the method f. -

+

For UTC2, we have -

+

  • UTC2 inherits from -
  • +
  • UTC1, which inherits from -
  • +
  • Object -
  • -
+ +

but the inheritance chain can be as long as you want. -

-
+

+
+ + diff --git a/Inheritance/inheritanceHow2.html b/Inheritance/inheritanceHow2.html index 943afbd..6d3edac 100644 --- a/Inheritance/inheritanceHow2.html +++ b/Inheritance/inheritanceHow2.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,23 +25,31 @@

How Inheritance Works -

+

Searching an inheritance chain may sound slow, but implementations of OO languages use a variety of - clever tricks to make that search run quite. -

+ clever tricks to make that search run quite fast. +

+

+ In a method call such as + x.f(3,4), + some details of that search depend upon whether + the type of x + is an interface type or a class type. + The details are a little simpler for a class type, + as when x is this, + so we consider that case first. +

A Java compiler can arrange all of the methods defined or inherited by a class into a linear sequence called the - - virtual method table. - - If the Java compiler sees a method call such as - x.f(3,4), where the type of x - is a class type, the compiler can use that type + virtual + method table. + When the type of x is a class type, + the compiler can use that type to figure out what the virtual method table for x will look like, and then searches that table at compile time to find the unique entry @@ -53,60 +61,62 @@

may be different from the type of x, but the compiler can compute the index of that entry at compile time. -

+

The compiler then generates machine code that, at run time, will obtain the virtual method table for x, use the index computed at compile time to fetch a pointer to the code for the f(int,int) method - of x, and jumps to that code. -

+ of x, and jump to that code. +

The machine code for x.f(3,4) will look something like this: -

+

       load    24(sp),r0     ; evaluate x into register r0
       loadi   3,r1          ; evaluate 3 into register r1
       loadi   4,r2          ; evaluate 4 into register r2
       load    8(r0),r3      ; fetch virtual method table
       load    368(r3),r3    ; fetch pointer to code for f
-      jmpi    (r3)          ; jump to code for f
-    
+ jmp (r3) ; jump to code for f +

That sequence of code should run very quickly. -

+

Note that the value of x is passed in register r0, which becomes the home of this within the machine code for f. -

+

The virtual method table may be fairly large, as suggested by the 368 in that example, but all objects of the same class will share the same virtual method table. -

+

Objects of different classes will have different virtual method tables, which is what allows methods to be overridden by subclasses. -

-

+

+
+ + diff --git a/Inheritance/inheritanceHow3.html b/Inheritance/inheritanceHow3.html index 950e1b8..70945df 100644 --- a/Inheritance/inheritanceHow3.html +++ b/Inheritance/inheritanceHow3.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,34 +25,36 @@

How Inheritance Works -

+

When the type of x is an interface type instead of a class type, a few more instructions may be needed to fetch the appropriate virtual method table at run time. -

+

The techniques used by compiler writers to make programs run fast are generally beyond the scope of this course, but we want you to know enough so you won't worry about how long it takes to look up an object's method. -

-
+

+
+ + diff --git a/Inheritance/inheritanceHow4.html b/Inheritance/inheritanceHow4.html index e503f27..61e504e 100644 --- a/Inheritance/inheritanceHow4.html +++ b/Inheritance/inheritanceHow4.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,33 +25,35 @@

Inheritance and this -

+

If a method in the superclass refers to this, where do you look for the method? -

+

Answer: in the original object. After all, this always refers to the original object, even within methods that are defined within a superclass of that object's class. -

-
+

+
+ + diff --git a/Inheritance/inheritanceHow5.html b/Inheritance/inheritanceHow5.html index fff2a7d..debf18d 100644 --- a/Inheritance/inheritanceHow5.html +++ b/Inheritance/inheritanceHow5.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,32 +25,34 @@

super -

+

Sometimes the subclass doesn't need to change the behavior of the superclass's method, but does need to add some additional behavior. -

+

In Java, any dynamic (non-static) method can call the f method of its superclass using the super.f(...) syntax. -

-
+

+
+ + diff --git a/Inheritance/inheritanceHow6.html b/Inheritance/inheritanceHow6.html index dbd0628..5bf9cfa 100644 --- a/Inheritance/inheritanceHow6.html +++ b/Inheritance/inheritanceHow6.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,32 +25,31 @@

this and super -

+

The rules for this and super can be summarized as: -

+

this is dynamic; super is static -

-

- That simple rule can lead to interesting behavior. -

-
+

+
+ + diff --git a/Inheritance/inheritanceJava1.html b/Inheritance/inheritanceJava1.html index 0a1397e..b56f653 100644 --- a/Inheritance/inheritanceJava1.html +++ b/Inheritance/inheritanceJava1.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,7 +25,7 @@

Inheritance in Java -

+
  • @@ -33,11 +33,11 @@

    class C1, write
               class C2 extends C1 ...
    -        
    + If no superclass of C2 is specified in this way, then the superclass of C2 is the predefined class Object. -

  • +
  • The Java constructor of a subclass always calls a Java constructor of its superclass. @@ -49,7 +49,7 @@

    If a Java constructor does not call a constructor of its superclass, the Java compiler automatically inserts a call of the form super(). -

  • +
  • If the compiler inserts super(), but the superclass does not define a constructor that @@ -57,23 +57,23 @@

    say it can't find the constructor you called, even though it is the compiler that's calling the constructor it can't find. -

  • +
  • If you don't define any constructors at all for a class, then the Java compiler automatically defines a constructor that takes no arguments and does nothing. -
  • -
- + + +
  • - A subclass can refer to the h field of its - superclass using the super.h syntax. -
  • + A subclass can refer to the x field of its + superclass using the super.x syntax. +
  • - A subclass can refer to the m method - of its superclass using the super.m + A subclass can refer to the f method + of its superclass using the super.f syntax. -
  • +
  • Java allows methods to be overridden without any annotation, but it is good programming practice to write @@ -87,24 +87,26 @@

    fails to override a method. That's helpful if you misspell the name of the method or get one of its argument types wrong. -

  • - - - -
    + + + + +
    + + diff --git a/Inheritance/inheritanceObjectives.html b/Inheritance/inheritanceObjectives.html index 3e7e152..c26f3c7 100644 --- a/Inheritance/inheritanceObjectives.html +++ b/Inheritance/inheritanceObjectives.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,38 +25,40 @@

    Learning Objectives -

    +

    By the end of this lesson, you should be able to: -

    +

    • define subclasses in Java -
    • +
    • define methods that override a default method defined in some superclass -
    • +
    • use super to invoke a Java constructor or method in the superclass -
    • -
    -
    + + +
    + + diff --git a/Inheritance/inheritanceSharing1.html b/Inheritance/inheritanceSharing1.html index df518ad..9b96040 100644 --- a/Inheritance/inheritanceSharing1.html +++ b/Inheritance/inheritanceSharing1.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,57 +25,63 @@

    Using Inheritance to Share Implementations -

    +

    Don't Repeat Yourself. -

    +

    If you implement some behavior by writing the same code at several different places in your program, that behavior will probably break when someone eventually tries to improve or repair it, and overlooks one of the several different places where that behavior needs to be updated. -

    +

    Inheritance allows several different classes to share a common implementation of their common behavior. -

    +

    Inheritance is often convenient, but it is also less general - and more fragile than composition and delegation. -

    + and more fragile than + composition and + delegation. +


    Creative Commons License - + © Mitchell Wand, 2012-2015
    This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License. - +
    The work has been modified by William D Clinger in these ways and more: conversion from PowerPoint to HTML, and from Racket to Java. -
    -
    + +
    + + diff --git a/Inheritance/inheritanceSharingMainIdeas.html b/Inheritance/inheritanceSharingMainIdeas.html index 9526657..883072b 100644 --- a/Inheritance/inheritanceSharingMainIdeas.html +++ b/Inheritance/inheritanceSharingMainIdeas.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,47 +25,49 @@

    Main Ideas -

    +

    A superclass can abstract over several classes. -

    +

    Inheritance allows classes to share the common parts of their implementations, by putting those common parts in a superclass. -

    +

    There are several alternatives for dealing with differences between the subclasses: -

    +

    • Subclasses can override methods defined in the superclass. -
    • +
    • Subclasses can define abstract methods declared in the superclass. -
    • +
    • A method defined in the superclass can call abstract help methods that are defined differently in the subclasses. This is called the template-and-hook pattern. -
    • -
    -
    + + +
    + + diff --git a/Inheritance/inheritanceSharingObjectives.html b/Inheritance/inheritanceSharingObjectives.html index a0c9727..85b3744 100644 --- a/Inheritance/inheritanceSharingObjectives.html +++ b/Inheritance/inheritanceSharingObjectives.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,40 +25,42 @@

    Learning Objectives -

    +

    By the end of this lesson, you should be able to: -

    +

    • identify common parts of class implementations -
    • +
    • generalize those common parts into a superclass -
    • +
    • identify the parts that differ, and turn them into abstract methods -
    • +
    • recover the original classes using inheritance -
    • -
    -
    + + +
    + + diff --git a/Inheritance/inheritanceSharingSummary.html b/Inheritance/inheritanceSharingSummary.html index 6255882..113b91c 100644 --- a/Inheritance/inheritanceSharingSummary.html +++ b/Inheritance/inheritanceSharingSummary.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -26,50 +26,52 @@

    Summary -

    +

    Here is the recipe for using inheritance to generalize similar classes: -

    +

    1. Move identical methods into a superclass. -
    2. +
    3. Make different methods into abstract methods.
      • Declare abstract methods in the superclass. -
      • +
      • Define abstract methods in the subclasses. -
      • -
      -
    4. + + +
    5. Generalize similar methods by adding abstract methods for the differences. -
    6. -
    + +

    Our UTC example was too simple to illustrate the third part of that recipe. The next several lessons go over a more substantial example. -

    -
    +

    + + + diff --git a/Inheritance/inheritanceSharingUTCa.html b/Inheritance/inheritanceSharingUTCa.html index c79d259..87e519c 100644 --- a/Inheritance/inheritanceSharingUTCa.html +++ b/Inheritance/inheritanceSharingUTCa.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,16 +25,16 @@

    The UTC Example -

    +

    In the - + previous lesson, - + we defined a class UTC2 that inherits several of its methods from another class UTC1. -

    +

    That use of inheritance was inelegant and somewhat fragile. Why does UTC2 inherit from UTC1 @@ -42,7 +42,7 @@

    What if some future programmer modifies UTC1 without realizing the modified behavior will be inherited by other classes such as UTC2? -

    +

    It would be more symmetrical, more elegant, and less fragile to define an abstract base class in which we implement @@ -53,21 +53,39 @@

    UTC1 and UTC2 would no longer be affected by changes to other concrete subclasses of the abstract base class. -

    -

    +

    +

    + The abstract base class will consist of field and method definitions + in which we implement the common behavior. + The abstract base class will also contain declarations of + abstract methods + that are not defined in the base class because they will have + differing behavior in the various subclasses. +

    +

    + Declaring an abstract method in the base class means + every (non-abstract) class that inherits from the base class + must provide a definition for the method. + We say the base class is abstract because some of its methods + are abstract (declared but not defined), so we cannot create + objects of the base class. +

    +
    + + diff --git a/Inheritance/inheritanceSharingUTCb.html b/Inheritance/inheritanceSharingUTCb.html index 3b54df4..630e0e7 100644 --- a/Inheritance/inheritanceSharingUTCb.html +++ b/Inheritance/inheritanceSharingUTCb.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -24,9 +24,11 @@
    +

    + Here is an abstract base class that can be used by classes + that implement the UTC interface. +

    -      // Abstract base class for classes that implement the UTC interface.
    -      
           abstract class UTC0 implements UTC {
           
               // this Java constructor has no fields to initialize
    @@ -68,21 +70,23 @@
                   return ((Integer) (100 * this.hour() + this.minute())).toString();
               }
           }
    -    
    -
    + +
    + + diff --git a/Inheritance/inheritanceSharingUTCc.html b/Inheritance/inheritanceSharingUTCc.html index 97c411e..fa49ff3 100644 --- a/Inheritance/inheritanceSharingUTCc.html +++ b/Inheritance/inheritanceSharingUTCc.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -27,7 +27,7 @@

    With most behavior implemented in the abstract base class, the UTC1 class becomes simpler: -

    +

           // Constructor template for UTC1:
           //     new UTC1 (h, m)
    @@ -66,21 +66,23 @@
                   UTC1tests.main(args);
               }
           }
    -    
    - + + + + diff --git a/Inheritance/inheritanceSharingUTCd.html b/Inheritance/inheritanceSharingUTCd.html index e8baa50..1d7038c 100644 --- a/Inheritance/inheritanceSharingUTCd.html +++ b/Inheritance/inheritanceSharingUTCd.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -26,7 +26,7 @@

    The UTC2 class becomes simpler as well: -

    +

           // Constructor template for UTC2:
           //     new UTC2 (h, m)
    @@ -47,6 +47,7 @@
               UTC2 (int h, int m) {
                   super ();    // calls the constructor for UTC0
                   this.h = (h >= 5) ? (h - 5) : h + 19;
    +              this.m = m;
               }
           
               // public methods
    @@ -73,21 +74,23 @@
                   UTC2tests.main(args);
               }
           }
    -    
    -
    + + + + diff --git a/Inheritance/inheritanceSharingUTCe.html b/Inheritance/inheritanceSharingUTCe.html index a2e6e43..280b24c 100644 --- a/Inheritance/inheritanceSharingUTCe.html +++ b/Inheritance/inheritanceSharingUTCe.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -26,28 +26,30 @@

    Fields can be Inherited -

    +

    We could simplify the concrete subclasses even more by defining the fields h and m in the base class, but that might be misleading because the interpretation of h is different in concrete classes UTC1 and UTC2. -

    -
    +

    + + + diff --git a/Inheritance/module11.html b/Inheritance/module11.html new file mode 100644 index 0000000..3edb0b1 --- /dev/null +++ b/Inheritance/module11.html @@ -0,0 +1,157 @@ + + + + + + + + + + + + CS 5010: Module 11 + + + + + + + + + + +
    +

    + CS 5010: Module 11 +

    +
    +

    + Module Overview +

    +

    + In this module, we will learn about inheritance, which is a + mechanism that allows us to generalize the implementations + of similar classes. Inheritance allows us to make a new class + that is very similar to an old one, or to make a new class + that generalizes the implementations of several similar classes. +

    +

    + Course Map +

    + course map +

    + Readings +

    +

    + No required readings. +

    +

    + Resources +

    + +

    + Lessons +

    + +

    + Problem Set +

    +

    + + Problem Set 11 + + will be assigned on Monday, 27 November. +

    +

    + Problem Set 11 will be the last problem set. +

    +
    +
    + + + + + + + diff --git a/InterfacesClasses/UTC1.html b/InterfacesClasses/UTC1.html index e4ea21d..6247885 100644 --- a/InterfacesClasses/UTC1.html +++ b/InterfacesClasses/UTC1.html @@ -28,8 +28,8 @@

    - This lesson defines a simple abstract data type - and develops a simple implementation of that ADT. + This lesson defines a simple data type + and develops a simple implementation of it.

    Subsequent lessons will improve and test that implementation. diff --git a/InterfacesClasses/functionsVsClasses10.html b/InterfacesClasses/functionsVsClasses10.html index 4b17f8d..c0f51dc 100644 --- a/InterfacesClasses/functionsVsClasses10.html +++ b/InterfacesClasses/functionsVsClasses10.html @@ -62,8 +62,8 @@

    // RETURNS: a scene like the given one, but with this // shape painted on it - public double addToScene (Scene sc) { - return Image.placeImage (img, x, y, s); + public Scene addToScene (Scene sc) { + return Image.placeImage (img, x, y, sc); } } diff --git a/InterfacesClasses/functionsVsClasses11.html b/InterfacesClasses/functionsVsClasses11.html index ec84572..9826a8e 100644 --- a/InterfacesClasses/functionsVsClasses11.html +++ b/InterfacesClasses/functionsVsClasses11.html @@ -56,7 +56,7 @@

    // RETURNS: a scene like the given one, but with this // shape painted on it - public double addToScene (Scene sc) { + public Scene addToScene (Scene sc) { return front.addToScene (back.addToScene (sc)); } } diff --git a/InterfacesClasses/functionsVsClasses3.html b/InterfacesClasses/functionsVsClasses3.html index 75f89f9..2a488d2 100644 --- a/InterfacesClasses/functionsVsClasses3.html +++ b/InterfacesClasses/functionsVsClasses3.html @@ -59,7 +59,7 @@

  • - weight : Shape Scene → Scene + add-to-scene : Shape Scene → Scene
    • RETURNS: a scene like the given one, except the given shape diff --git a/InterfacesClasses/functionsVsClasses9.html b/InterfacesClasses/functionsVsClasses9.html index 601d86b..53a75f6 100644 --- a/InterfacesClasses/functionsVsClasses9.html +++ b/InterfacesClasses/functionsVsClasses9.html @@ -62,8 +62,8 @@

      // RETURNS: a scene like the given one, but with this // shape painted on it - public double addToScene (Scene sc) { - return Image.placeImage (img, x, y, s); + public Scene addToScene (Scene sc) { + return Image.placeImage (img, x, y, sc); } } diff --git a/InterfacesClasses2/UTC1.html b/InterfacesClasses2/UTC1.html new file mode 100644 index 0000000..6247885 --- /dev/null +++ b/InterfacesClasses2/UTC1.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + Case Study: Universal Coordinated Time (UTC) + + + + + + + + + + +
      +

      + Case Study: Universal Coordinated Time (UTC) +

      +
      +

      + This lesson defines a simple data type + and develops a simple implementation of it. +

      +

      + Subsequent lessons will improve and test that implementation. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC10.html b/InterfacesClasses2/UTC10.html new file mode 100644 index 0000000..4d763ed --- /dev/null +++ b/InterfacesClasses2/UTC10.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + Compiling and Testing the UTC1 Class + + + + + + + + + + +
      +
      +

      + To compile and run the UTC1 class, + use the Unix cd command to change + to the directory that contains the UTC1.java file. + Then say: +

      +
      +      javac UTC1.java
      +      
      +      java -enableassertions UTC1
      +
      +

      + The javac command in the first line + compiles the UTC1.java file + along with any other files it needs. + The java command in the second line + runs the program by calling the + static main method defined within the + UTC1 class. +

      +
      +

      + The javac command compiles one or more files, + so you have to specify a file name. +

      +

      + The java command runs the main + defined by a class, so you have to specify a class name. + Note that Java file names end with .java, but + Java class names do not. +

      +
      +

      + The -enableassertions option is necessary + because Java assertions are disabled by default. + If you forget to specify the -enableassertions option, + the program will run and tell you all tests have passed, + but it won't actually run any of the tests. +

      +

      + Assertions are not the best way to test a Java program. + One disadvantage of using assertions for testing is that + you find only bug at a time: When one assertion fails, + none of the tests that follow the failed assertion will run. +

      +

      + We have shown you how to use assertions for testing because + assertions are easy to explain. + When we test your programs, we will use a testing framework + we have written especially for this course. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC1summary.html b/InterfacesClasses2/UTC1summary.html new file mode 100644 index 0000000..f294abe --- /dev/null +++ b/InterfacesClasses2/UTC1summary.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + Summary + + + + + + + + + + +
      +
      +

      + Summary +

      +
        +
      • + data types are interfaces; interfaces are data types +
      • +
      • + interfaces are implemented by classes +
      • +
      • + all of a class's methods should be tested +
      • +
      • + assertions can be used for testing +
      • +
      • + Java assertions are disabled by default, + so you have to specify the -enableassertions option + when you run your program +
      • +
      • + execution of a Java program starts by calling + a static main method +
      • +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC2.html b/InterfacesClasses2/UTC2.html new file mode 100644 index 0000000..40f640e --- /dev/null +++ b/InterfacesClasses2/UTC2.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + Learning Objectives + + + + + + + + + + +
      +

      + Learning Objectives +

      +
      +

      + You already know how to: +

      +
        +
      • + define simple interfaces in Java +
      • +
      • + define classes that implement those interfaces +
      • +
      +

      + By the end of this lesson, you should be able to: +

      +
        +
      • + write simple tests of your classes +
      • +
      • + write a complete Java program +
      • +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC3.html b/InterfacesClasses2/UTC3.html new file mode 100644 index 0000000..553e1cb --- /dev/null +++ b/InterfacesClasses2/UTC3.html @@ -0,0 +1,76 @@ + + + + + + + + + + + + Definition of the UTC ADT + + + + + + + + + + +
      +
      +

      + First, we define an interface: +

      +
      +      // A UTC is an object of any class that implements UTC.
      +      //
      +      // Interpretation: A UTC represents a Universal Coordinated Time.
      +      
      +      interface UTC {
      +      
      +          // Returns the hour, between 0 and 23 inclusive.
      +      
      +          int hour ();
      +      
      +          // Returns the minute, between 0 and 59 inclusive.
      +      
      +          int minute ();
      +      
      +          // Returns true iff the given UTC is equal to this UTC.
      +      
      +          boolean isEqual (UTC t2);
      +      }
      +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC4.html b/InterfacesClasses2/UTC4.html new file mode 100644 index 0000000..f181ab2 --- /dev/null +++ b/InterfacesClasses2/UTC4.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + An Implementation of UTC + + + + + + + + + + +
      +
      +

      + Then we define a class that implements that interface: +

      +
      +      // Constructor template for UTC1:
      +      //     new UTC1 (h, m)
      +      // Interpretation:
      +      //     h is the hour (between 0 and 23, inclusive)
      +      //     m is the minute (between 0 and 59, inclusive)
      +      
      +      class UTC1 implements UTC {
      +      
      +          int h;    // the hour, limited to [0,23]
      +          int m;    // the minute, limited to [0,59]
      +      
      +          // the Java constructor
      +      
      +          UTC1 (int h, int m) {
      +              this.h = h;
      +              this.m = m;
      +          }
      +      
      +          // public methods
      +      
      +          // Returns the hour, between 0 and 23 inclusive.
      +      
      +          public int hour () { return h; }
      +      
      +          // Returns the minute, between 0 and 59 inclusive.
      +      
      +          public int minute () { return m; }
      +      
      +          // Returns true iff the given UTC is equal to this UTC.
      +      
      +          public boolean isEqual (UTC t2) {
      +              return (h == t2.hour()) && (m == t2.minute());
      +          }
      +      
      +          ...
      +      }
      +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC5.html b/InterfacesClasses2/UTC5.html new file mode 100644 index 0000000..af95b2b --- /dev/null +++ b/InterfacesClasses2/UTC5.html @@ -0,0 +1,70 @@ + + + + + + + + + + + + Static Methods + + + + + + + + + + +
      +
      +

      + To test our UTC1 class, + we'll need to define a main method. +

      +

      + That main method will be static, + which means the method exists independently of any objects. + It is part of the class in which it is defined, + but it is not part of any object. +

      +

      + At the beginning of a Java program, there are no objects, + so the program has to start by calling a method that + isn't part of an object. + That's why a Java program's main method + is always static. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC6.html b/InterfacesClasses2/UTC6.html new file mode 100644 index 0000000..4ae5937 --- /dev/null +++ b/InterfacesClasses2/UTC6.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + Static Methods + + + + + + + + + + +
      +
      +

      + The main method of a Java program + must be declared public and static. + The main method won't return anything, + so its return type is void. + The main method takes one argument, + which is an array of strings representing + parameters passed on the command line, if any. +

      +

      + For example: +

      +
      +          public static void main (String[] args) {
      +              UTC1tests.main(args);
      +          }
      +
      +

      + The body of that main method calls the static + main method defined in the + UTC1tests class, + which we will define momentarily. +

      +

      + When calling a static method, there is no receiver object. + In place of writing an expression that evaluates to the + receiver, we write the name of the class that defines the + static method. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC7.html b/InterfacesClasses2/UTC7.html new file mode 100644 index 0000000..8837cd1 --- /dev/null +++ b/InterfacesClasses2/UTC7.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + The UTC1 Class + + + + + + + + + + +
      +
      +

      + Here is the entire definition of the UTC1 class: +

      +
      +      // Constructor template for UTC1:
      +      //     new UTC1 (h, m)
      +      // Interpretation:
      +      //     h is the hour (between 0 and 23, inclusive)
      +      //     m is the minute (between 0 and 59, inclusive)
      +      
      +      class UTC1 implements UTC {
      +      
      +          int h;    // the hour, limited to [0,23]
      +          int m;    // the minute, limited to [0,59]
      +      
      +          // the Java constructor
      +      
      +          UTC1 (int h, int m) {
      +              this.h = h;
      +              this.m = m;
      +          }
      +      
      +          // public methods
      +      
      +          // Returns the hour, between 0 and 23 inclusive.
      +      
      +          public int hour () { return h; }
      +      
      +          // Returns the minute, between 0 and 59 inclusive.
      +      
      +          public int minute () { return m; }
      +      
      +          // Returns true iff the given UTC is equal to this UTC.
      +      
      +          public boolean isEqual (UTC t2) {
      +              return (h == t2.hour()) && (m == t2.minute());
      +          }
      +      
      +          // a main method for unit testing
      +      
      +          public static void main (String[] args) {
      +              UTC1tests.main(args);
      +          }
      +      }
      +
      +

      + Before we can compile this program, + we have to define the UTC1tests class. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/UTC9.html b/InterfacesClasses2/UTC9.html new file mode 100644 index 0000000..8687265 --- /dev/null +++ b/InterfacesClasses2/UTC9.html @@ -0,0 +1,101 @@ + + + + + + + + + + + + The UTC1 Class + + + + + + + + + + +
      +
      +
      +      // Unit tests for UTC1.
      +      
      +      class UTC1tests {
      +      
      +          // a main method for testing UTC objects
      +      
      +          public static void main (String[] args) {
      +              UTC t1 = new UTC1 (15, 31);
      +              UTC t2 = new UTC1 (14, 31);
      +              UTC t3 = new UTC1 (15, 32);
      +              UTC t4 = new UTC1 (15, 31);
      +      
      +              assert t1.hour() == 15 : "wrong hour for t1";
      +              assert t1.minute() == 31 : "wrong minute for t1";
      +      
      +              assert t1.isEqual (t1) : "isEqual says this doesn't equal this";
      +              assert t1.isEqual (t4) : "isEqual says this doesn't equal that";
      +              assert ! (t1.isEqual (t2)) : "isEqual true but hour different";
      +              assert ! (t1.isEqual (t3)) : "isEqual true but minute different";
      +      
      +              System.out.println ("All unit tests of UTC1 passed.");
      +          }
      +      }
      +
      +

      + That main method uses assertions + for testing. + Each assertion consists of: +

      +
        +
      • + the word assert +
      • +
      • + followed by an expression that should evaluate to true +
      • +
      • + followed by a colon +
      • +
      • + followed by an error message that will be printed + if the expression evaluates to false +
      • +
      • + followed by the semicolon that terminates the assertion +
      • +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/abstractDataTypes1.html b/InterfacesClasses2/abstractDataTypes1.html new file mode 100644 index 0000000..d5de410 --- /dev/null +++ b/InterfacesClasses2/abstractDataTypes1.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + Abstract Data Types + + + + + + + + + + +
      +

      + Abstract Data Types +

      +
      +

      + In this module, we will introduce the notion of an + abstract data type (ADT). + We will discuss equality and representation independence + for abstract data types, + and use those concepts to motivate specific features of Java. +

      +
      +
      + + Creative Commons License + + © Mitchell Wand, 2012-2015 +
      + This work is licensed under a + + Creative Commons Attribution-NonCommercial 4.0 International + License. + +
      + The work has been modified by William D Clinger in these ways + and more: + conversion from PowerPoint to HTML, and from Racket to Java. +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/abstractDataTypesObjectives.html b/InterfacesClasses2/abstractDataTypesObjectives.html new file mode 100644 index 0000000..4f5e0b4 --- /dev/null +++ b/InterfacesClasses2/abstractDataTypesObjectives.html @@ -0,0 +1,76 @@ + + + + + + + + + + + + Learning Objectives + + + + + + + + + + +
      +

      + Learning Objectives +

      +
      +

      + By the end of this lesson, you should be able to: +

      +
        +
      • + explain the difference between concrete and abstract data types +
      • +
      • + give examples of concrete data types +
      • +
      • + give examples of abstract data types +
      • +
      • + list advantages of abstract data types +
      • +
      • + explain how abstract data types can be specified +
      • +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/abstractDataTypesSummary.html b/InterfacesClasses2/abstractDataTypesSummary.html new file mode 100644 index 0000000..effc1d2 --- /dev/null +++ b/InterfacesClasses2/abstractDataTypesSummary.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + Lesson Summary + + + + + + + + + + +
      +

      + Summary +

      +
      +

      + In this lesson, you've learned: +

      +
        +
      • + the difference between concrete and abstract data types +
      • +
      • + how abstraction barriers determine that distinction +
      • +
      • + examples of concrete data types +
      • +
      • + examples of abstract data types +
      • +
      • + advantages of abstract data types +
      • +
      • + how abstract data types are specified +
      • +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/abstractionBarrier1.html b/InterfacesClasses2/abstractionBarrier1.html new file mode 100644 index 0000000..dfbeb4b --- /dev/null +++ b/InterfacesClasses2/abstractionBarrier1.html @@ -0,0 +1,92 @@ + + + + + + + + + + + + Abstraction Barrier + + + + + + + + + + +
      +

      + Abstraction Barrier +

      +
      +

      + Abstract data types introduce an + abstraction barrier + between those who implement a data type + and those who use it. +

      +

      + If you are implementing the data type, + then you know how its values are represented + and are allowed to write code that depends upon + that representation. +

      +

      + If you are a user of an abstract data type, + then you do not know how its values are represented + and you are not allowed to write code that depends upon + the representation. +

      +
      + That means the distinction between concrete and abstract + data types depends on your relationship to the data type. +
      +

      + If a problem set asks you to implement a data type, then + you will know its representation and can rely on that knowledge + when you write your tests and define your functions and methods. + For you, the data type will be concrete. +

      +

      + When we write black-box tests of a data type we have asked + you to design and to implement, we will not know its + representation, and our black-box tests are not allowed to + depend on any properties or behavior of the data type beyond + the properties and behavior specified in the problem set. + For the course staff, the data type will be abstract. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/abstractionBarrier2.html b/InterfacesClasses2/abstractionBarrier2.html new file mode 100644 index 0000000..916b961 --- /dev/null +++ b/InterfacesClasses2/abstractionBarrier2.html @@ -0,0 +1,75 @@ + + + + + + + + + + + + Abstraction Barrier + + + + + + + + + + +
      +

      + Abstraction Barrier +

      +
      +

      + To determine whether a data type is concrete or abstract, + you must know which side of its abstraction barrier + you're on. +

      +

      + When you are designing a representation for some data type, + the data type is concrete. +

      +

      + When you are defining the basic functions and methods that + other programmers will use to manipulate a data type you + have designed, that data type is concrete. +

      +

      + When you are using a data type defined and implemented + by others, that data type may be abstract for you + even though it was a concrete data type for its implementors. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/abstractionBarrier3.html b/InterfacesClasses2/abstractionBarrier3.html new file mode 100644 index 0000000..a472511 --- /dev/null +++ b/InterfacesClasses2/abstractionBarrier3.html @@ -0,0 +1,85 @@ + + + + + + + + + + + + Abstraction Barrier + + + + + + + + + + +
      +

      + Abstraction Barrier +

      +
      +

      + It is not unusual for programmers to use an abstract data type + they themselves have helped to implement. + When they were implementing that data type, it was + (for them at that time) + a concrete data type. +

      +

      + When those same programmers use that abstract data type + in the way it was intended to be used by others, + it is an abstract data type. +

      +

      + This often causes confusion + among inexperienced programmers, and sometime even among + experienced programmers. + To reduce that confusion, and to reduce errors caused by + that confusion, modern programming languages make it + possible to hide the representation of an abstract data type + from programmers who should not be relying upon that + representation. +

      +
      +

      + When the data type is defined by a Java interface, + the Java compiler prevents you from relying upon + the representation of its values. +

      +
      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/advantagesADT1.html b/InterfacesClasses2/advantagesADT1.html new file mode 100644 index 0000000..b96d6d3 --- /dev/null +++ b/InterfacesClasses2/advantagesADT1.html @@ -0,0 +1,118 @@ + + + + + + + + + + + + Advantages of Abstract Data Types + + + + + + + + + + +
      +

      + Advantages of Abstract Data Types +

      +
      +

      + Abstract data types offer several advantages + over concrete data types: +

      +
        +
      • + Representation Independence: + Most of the program becomes independent of + the abstract data type's representation, + so that representation can be improved + without breaking the entire program. +
      • +
      • + Modularity: + With representation independence, the different parts + of a program become less dependent on other parts + and on how those other parts are implemented. +
      • +
      • + Interchangeability of Parts: + Different implementations of an abstract data type + may have different performance characteristics. + With abstract data types, it becomes easier + for each part of a program to use an implementation + of its data types that will be more efficient for + that particular part of the program. +
      • +
      +
      +

      + Example: +

      +

      + Java's standard libraries supply several different + implementations of its Map data type. + The TreeMap implementation might be + more efficient when a total ordering on the keys + can be computed quickly but a good hash value is + hard to compute efficiently. + The HashMap implementation might be + more efficient when hash values can be computed + quickly and there is no obvious ordering on keys. + The part of a program that creates a Map + can decide which implementation to use. + The parts of a program that deal with a created + Map don't have to know how it was + implemented; once created, it's just a Map. +

      +

      + If it weren't for abstract data types, every part + of the program that uses a Map would + have to be written twice, with one version to deal with + TreeMap implementations + and another version to deal with + HashMap implementations. +

      +
      +

      + These advantages become more important in larger programs, + so they often go under-appreciated by programmers with + limited experience. +

      +
      +
      + + + + + + + + diff --git a/InterfacesClasses2/angular.min.js b/InterfacesClasses2/angular.min.js new file mode 100644 index 0000000..f17382b --- /dev/null +++ b/InterfacesClasses2/angular.min.js @@ -0,0 +1,201 @@ +/* + AngularJS v1.2.5 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(W,N,r){'use strict';function G(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.2.5/"+(b?b+"/":"")+a;for(c=1;c").append(b).html();try{return 3===b[0].nodeType?v(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+v(b)})}catch(d){return v(c)}}function Ub(b){try{return decodeURIComponent(b)}catch(a){}} +function Vb(b){var a={},c,d;q((b||"").split("&"),function(b){b&&(c=b.split("="),d=Ub(c[0]),z(d)&&(b=z(c[1])?Ub(c[1]):!0,a[d]?L(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Wb(b){var a=[];q(b,function(b,d){L(b)?q(b,function(b){a.push(va(d,!0)+(!0===b?"":"="+va(b,!0)))}):a.push(va(d,!0)+(!0===b?"":"="+va(b,!0)))});return a.length?a.join("&"):""}function sb(b){return va(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function va(b,a){return encodeURIComponent(b).replace(/%40/gi, +"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function Sc(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,f=["ng:app","ng-app","x-ng-app","data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;q(f,function(a){f[a]=!0;c(N.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(q(b.querySelectorAll("."+a),c),q(b.querySelectorAll("."+a+"\\:"),c),q(b.querySelectorAll("["+a+"]"),c))});q(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,g= +(b[2]||"").replace(/\s+/g,",")):q(a.attributes,function(b){!e&&f[b.name]&&(e=a,g=b.value)})}});e&&a(e,g?[g]:[])}function Xb(b,a){var c=function(){b=x(b);if(b.injector()){var c=b[0]===N?"document":ha(b);throw Na("btstrpd",c);}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=Yb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate",function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/; +if(W&&!d.test(W.name))return c();W.name=W.name.replace(d,"");Pa.resumeBootstrap=function(b){q(b,function(b){a.push(b)});c()}}function cb(b,a){a=a||"_";return b.replace(Tc,function(b,d){return(d?a:"")+b.toLowerCase()})}function tb(b,a,c){if(!b)throw Na("areq",a||"?",c||"required");return b}function Qa(b,a,c){c&&L(b)&&(b=b[b.length-1]);tb(A(b),a,"not a function, got "+(b&&"object"==typeof b?b.constructor.name||"Object":typeof b));return b}function wa(b,a){if("hasOwnProperty"===b)throw Na("badname", +a);}function ub(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,g=a.length,f=0;f 

  • "+b;a.removeChild(a.firstChild);yb(this,a.childNodes);x(N.createDocumentFragment()).append(this)}else yb(this,b)}function zb(b){return b.cloneNode(!0)}function Da(b){Zb(b);var a=0;for(b=b.childNodes|| +[];a=E?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function Ea(b){var a=typeof b,c;"object"==a&&null!==b?"function"==typeof(c=b.$$hashKey)?c=b.$$hashKey():c===r&&(c=b.$$hashKey=Za()):c=b;return a+":"+c}function Ta(b){q(b,this.put,this)} +function fc(b){var a,c;"function"==typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(Zc,""),c=c.match($c),q(c[1].split(ad),function(b){b.replace(bd,function(b,c,d){a.push(d)})})),b.$inject=a):L(b)?(c=b.length-1,Qa(b[c],"fn"),a=b.slice(0,c)):Qa(b,"fn",!0);return a}function Yb(b){function a(a){return function(b,c){if(U(b))q(b,Pb(a));else return a(b,c)}}function c(a,b){wa(a,"service");if(A(b)||L(b))b=n.instantiate(b);if(!b.$get)throw Ua("pget",a);return m[a+h]=b}function d(a,b){return c(a, +{$get:b})}function e(a){var b=[],c,d,h,g;q(a,function(a){if(!k.get(a)){k.put(a,!0);try{if(D(a))for(c=Va(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,h=0,g=d.length;h 4096 bytes)!")); +else{if(l.cookie!==X)for(X=l.cookie,d=X.split("; "),Y={},g=0;gk&&this.remove(p.key),b},get:function(a){var b=m[a];if(b)return e(b),l[a]},remove:function(a){var b=m[a];b&&(b==n&&(n=b.p),b==p&&(p=b.n),g(b.n,b.p),delete m[a], +delete l[a],f--)},removeAll:function(){l={};f=0;m={};n=p=null},destroy:function(){m=h=l=null;delete a[b]},info:function(){return w({},h,{size:f})}}}var a={};b.info=function(){var b={};q(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function gd(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function hc(b,a){var c={},d="Directive",e=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,g=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,f=/^(on[a-z]+|formaction)$/;this.directive= +function l(a,e){wa(a,"directive");D(a)?(tb(e,"directiveFactory"),c.hasOwnProperty(a)||(c[a]=[],b.factory(a+d,["$injector","$exceptionHandler",function(b,d){var e=[];q(c[a],function(c,g){try{var f=b.invoke(c);A(f)?f={compile:ca(f)}:!f.compile&&f.link&&(f.compile=ca(f.link));f.priority=f.priority||0;f.index=g;f.name=f.name||a;f.require=f.require||f.controller&&f.name;f.restrict=f.restrict||"A";e.push(f)}catch(l){d(l)}});return e}])),c[a].push(e)):q(a,Pb(l));return this};this.aHrefSanitizationWhitelist= +function(b){return z(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return z(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(a,b,m,n,p,t,C,B,K,u,P,Z){function y(a,b,c,d,e){a instanceof x||(a=x(a));q(a,function(b,c){3==b.nodeType&& +b.nodeValue.match(/\S+/)&&(a[c]=x(b).wrap("").parent()[0])});var g=Q(a,b,a,c,d,e);return function(b,c,d){tb(b,"scope");var e=c?Fa.clone.call(a):a;q(d,function(a,b){e.data("$"+b+"Controller",a)});d=0;for(var f=e.length;darguments.length&&(b=a,a=r);Ha&&(c=O);return n(a,b,c)}var y,da,Y,u,$,J,O={},X;y=c===g?d:Qc(d,new Eb(x(g),d.$attr));da=y.$$element;if(Q){var S=/^\s*([@=&])(\??)\s*(\w*)\s*$/;f=x(g);J=e.$new(!0);M&& +M===Q.$$originalDirective?f.data("$isolateScope",J):f.data("$isolateScopeNoTemplate",J);ba(f,"ng-isolate-scope");q(Q.scope,function(a,c){var d=a.match(S)||[],g=d[3]||c,f="?"==d[2],d=d[1],l,m,n,p;J.$$isolateBindings[c]=d+g;switch(d){case "@":y.$observe(g,function(a){J[c]=a});y.$$observers[g].$$scope=e;y[g]&&(J[c]=b(y[g])(e));break;case "=":if(f&&!y[g])break;m=t(y[g]);p=m.literal?ta:function(a,b){return a===b};n=m.assign||function(){l=J[c]=m(e);throw ia("nonassign",y[g],Q.name);};l=J[c]=m(e);J.$watch(function(){var a= +m(e);p(a,J[c])||(p(a,l)?n(e,a=J[c]):J[c]=a);return l=a},null,m.literal);break;case "&":m=t(y[g]);J[c]=function(a){return m(e,a)};break;default:throw ia("iscp",Q.name,c,a);}})}X=n&&B;Z&&q(Z,function(a){var b={$scope:a===Q||a.$$isolateScope?J:e,$element:da,$attrs:y,$transclude:X},c;$=a.controller;"@"==$&&($=y[a.name]);c=C($,b);O[a.name]=c;Ha||da.data("$"+a.name+"Controller",c);a.controllerAs&&(b.$scope[a.controllerAs]=c)});f=0;for(Y=l.length;f +F.priority)break;if(v=F.scope)u=u||F,F.templateUrl||(H("new/isolated scope",Q,F,s),U(v)&&(Q=F));ea=F.name;!F.templateUrl&&F.controller&&(v=F.controller,Z=Z||{},H("'"+ea+"' controller",Z[ea],F,s),Z[ea]=F);if(v=F.transclude)la=!0,F.$$tlb||(H("transclusion",n,F,s),n=F),"element"==v?(Ha=!0,Y=F.priority,v=$(c,xa,gb),s=d.$$element=x(N.createComment(" "+ea+": "+d[ea]+" ")),c=s[0],R(g,x(ua.call(v,0)),c),w=y(v,e,Y,f&&f.name,{nonTlbTranscludeDirective:n})):(v=x(zb(c)).contents(),s.empty(),w=y(v,e));if(F.template)if(H("template", +M,F,s),M=F,v=A(F.template)?F.template(s,d):F.template,v=ic(v),F.replace){f=F;v=x("
    "+aa(v)+"
    ").contents();c=v[0];if(1!=v.length||1!==c.nodeType)throw ia("tplrt",ea,"");R(g,s,c);E={$attr:{}};v=X(c,[],E);var V=a.splice(I+1,a.length-(I+1));Q&&S(v);a=a.concat(v).concat(V);gc(d,E);E=a.length}else s.html(v);if(F.templateUrl)H("template",M,F,s),M=F,F.replace&&(f=F),K=z(a.splice(I,a.length-I),s,d,g,w,l,p,{controllerDirectives:Z,newIsolateScopeDirective:Q,templateDirective:M,nonTlbTranscludeDirective:n}), +E=a.length;else if(F.compile)try{G=F.compile(s,d,w),A(G)?B(null,G,xa,gb):G&&B(G.pre,G.post,xa,gb)}catch(W){m(W,ha(s))}F.terminal&&(K.terminal=!0,Y=Math.max(Y,F.priority))}K.scope=u&&!0===u.scope;K.transclude=la&&w;return K}function S(a){for(var b=0,c=a.length;bt.priority)&&-1!=t.restrict.indexOf(g)&&(n&&(t=Rb(t, +{$$start:n,$$end:p})),b.push(t),k=t)}catch(y){m(y)}}return k}function gc(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;q(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});q(b,function(b,g){"class"==g?(ba(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==g?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==g.charAt(0)||a.hasOwnProperty(g)||(a[g]=b,d[g]=c[g])})}function z(a,b,c,d,e,g,f,k){var l=[],m,t,C=b[0],B=a.shift(), +y=w({},B,{templateUrl:null,transclude:null,replace:null,$$originalDirective:B}),P=A(B.templateUrl)?B.templateUrl(b,c):B.templateUrl;b.empty();n.get(u.getTrustedResourceUrl(P),{cache:p}).success(function(n){var p,K;n=ic(n);if(B.replace){n=x("
    "+aa(n)+"
    ").contents();p=n[0];if(1!=n.length||1!==p.nodeType)throw ia("tplrt",B.name,P);n={$attr:{}};R(d,b,p);var u=X(p,[],n);U(B.scope)&&S(u);a=u.concat(a);gc(c,n)}else p=C,b.html(n);a.unshift(y);m=M(a,p,c,e,b,B,g,f,k);q(d,function(a,c){a==p&&(d[c]= +b[0])});for(t=Q(b[0].childNodes,e);l.length;){n=l.shift();K=l.shift();var ba=l.shift(),Z=l.shift(),u=b[0];K!==C&&(u=zb(p),R(ba,x(K),u));K=m.transclude?Y(n,m.transclude):Z;m(t,n,u,d,K)}l=null}).error(function(a,b,c,d){throw ia("tpload",d.url);});return function(a,b,c,d,e){l?(l.push(b),l.push(c),l.push(d),l.push(e)):m(t,b,c,d,e)}}function s(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.namea.status?b:n.reject(b)}var d={transformRequest:e.transformRequest,transformResponse:e.transformResponse},g=function(a){function b(a){var c;q(a,function(b,d){A(b)&&(c=b(),null!=c?a[d]=c:delete a[d])})}var c=e.headers,d=w({},a.headers),g,f,c=w({},c.common,c[v(a.method)]);b(c);b(d);a:for(g in c){a=v(g);for(f in d)if(v(f)===a)continue a;d[g]=c[g]}return d}(a);w(d,a);d.headers=g;d.method=Ia(d.method);(a=Fb(d.url)?b.cookies()[d.xsrfCookieName|| +e.xsrfCookieName]:r)&&(g[d.xsrfHeaderName||e.xsrfHeaderName]=a);var f=[function(a){g=a.headers;var b=mc(a.data,lc(g),a.transformRequest);H(a.data)&&q(g,function(a,b){"content-type"===v(b)&&delete g[b]});H(a.withCredentials)&&!H(e.withCredentials)&&(a.withCredentials=e.withCredentials);return C(a,b,g).then(c,c)},r],h=n.when(d);for(q(u,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift(); +var k=f.shift(),h=h.then(a,k)}h.success=function(a){h.then(function(b){a(b.data,b.status,b.headers,d)});return h};h.error=function(a){h.then(null,function(b){a(b.data,b.status,b.headers,d)});return h};return h}function C(b,c,g){function f(a,b,c){u&&(200<=a&&300>a?u.put(r,[a,b,kc(c)]):u.remove(r));l(b,a,c);d.$$phase||d.$apply()}function l(a,c,d){c=Math.max(c,0);(200<=c&&300>c?p.resolve:p.reject)({data:a,status:c,headers:lc(d),config:b})}function k(){var a=bb(t.pendingRequests,b);-1!==a&&t.pendingRequests.splice(a, +1)}var p=n.defer(),C=p.promise,u,q,r=B(b.url,b.params);t.pendingRequests.push(b);C.then(k,k);(b.cache||e.cache)&&(!1!==b.cache&&"GET"==b.method)&&(u=U(b.cache)?b.cache:U(e.cache)?e.cache:K);if(u)if(q=u.get(r),z(q)){if(q.then)return q.then(k,k),q;L(q)?l(q[1],q[0],ga(q[2])):l(q,200,{})}else u.put(r,C);H(q)&&a(b.method,r,c,f,g,b.timeout,b.withCredentials,b.responseType);return C}function B(a,b){if(!b)return a;var c=[];Nc(b,function(a,b){null===a||H(a)||(L(a)||(a=[a]),q(a,function(a){U(a)&&(a=oa(a)); +c.push(va(b)+"="+va(a))}))});return a+(-1==a.indexOf("?")?"?":"&")+c.join("&")}var K=c("$http"),u=[];q(g,function(a){u.unshift(D(a)?p.get(a):p.invoke(a))});q(f,function(a,b){var c=D(a)?p.get(a):p.invoke(a);u.splice(b,0,{response:function(a){return c(n.when(a))},responseError:function(a){return c(n.reject(a))}})});t.pendingRequests=[];(function(a){q(arguments,function(a){t[a]=function(b,c){return t(w(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){q(arguments,function(a){t[a]= +function(b,c,d){return t(w(d||{},{method:a,url:b,data:c}))}})})("post","put");t.defaults=e;return t}]}function nd(){this.$get=["$browser","$window","$document",function(b,a,c){return od(b,pd,b.defer,a.angular.callbacks,c[0])}]}function od(b,a,c,d,e){function g(a,b){var c=e.createElement("script"),d=function(){c.onreadystatechange=c.onload=c.onerror=null;e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;E&&8>=E?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}: +c.onload=c.onerror=function(){d()};e.body.appendChild(c);return d}var f=-1;return function(e,l,k,m,n,p,t,C){function B(){u=f;r&&r();y&&y.abort()}function K(a,d,e,g){var f=ya(l).protocol;ba&&c.cancel(ba);r=y=null;d="file"==f&&0===d?e?200:404:d;a(1223==d?204:d,e,g);b.$$completeOutstandingRequest(s)}var u;b.$$incOutstandingRequestCount();l=l||b.url();if("jsonp"==v(e)){var P="_"+(d.counter++).toString(36);d[P]=function(a){d[P].data=a};var r=g(l.replace("JSON_CALLBACK","angular.callbacks."+P),function(){d[P].data? +K(m,200,d[P].data):K(m,u||-2);delete d[P]})}else{var y=new a;y.open(e,l,!0);q(n,function(a,b){z(a)&&y.setRequestHeader(b,a)});y.onreadystatechange=function(){if(4==y.readyState){var a=null,b=null;u!==f&&(a=y.getAllResponseHeaders(),b=y.responseType?y.response:y.responseText);K(m,u||y.status,b,a)}};t&&(y.withCredentials=!0);C&&(y.responseType=C);y.send(k||null)}if(0=h&&(n.resolve(t),m(p.$$intervalId),delete e[p.$$intervalId]);C||b.$apply()},f);e[p.$$intervalId]=n;return p}var e={};d.cancel=function(a){return a&&a.$$intervalId in e?(e[a.$$intervalId].reject("canceled"),clearInterval(a.$$intervalId),delete e[a.$$intervalId],!0):!1};return d}]}function sd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3, +lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a", +fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function oc(b){b=b.split("/");for(var a=b.length;a--;)b[a]=sb(b[a]);return b.join("/")}function pc(b,a,c){b=ya(b,c);a.$$protocol=b.protocol;a.$$host=b.hostname;a.$$port=R(b.port)||td[b.protocol]||null}function qc(b,a,c){var d="/"!==b.charAt(0);d&&(b="/"+b);b=ya(b,c);a.$$path=decodeURIComponent(d&&"/"===b.pathname.charAt(0)? +b.pathname.substring(1):b.pathname);a.$$search=Vb(b.search);a.$$hash=decodeURIComponent(b.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function na(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Wa(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function Gb(b){return b.substr(0,Wa(b).lastIndexOf("/")+1)}function rc(b,a){this.$$html5=!0;a=a||"";var c=Gb(b);pc(b,this,b);this.$$parse=function(a){var e=na(c,a);if(!D(e))throw Hb("ipthprfx",a,c);qc(e,this,b);this.$$path|| +(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Wb(this.$$search),b=this.$$hash?"#"+sb(this.$$hash):"";this.$$url=oc(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$rewrite=function(d){var e;if((e=na(b,d))!==r)return d=e,(e=na(a,e))!==r?c+(na("/",e)||e):b+d;if((e=na(c,d))!==r)return c+e;if(c==d+"/")return c}}function Ib(b,a){var c=Gb(b);pc(b,this,b);this.$$parse=function(d){var e=na(b,d)||na(c,d),e="#"==e.charAt(0)?na(a,e):this.$$html5?e:"";if(!D(e))throw Hb("ihshprfx", +d,a);qc(e,this,b);d=this.$$path;var g=/^\/?.*?:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));g.exec(e)||(d=(e=g.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Wb(this.$$search),e=this.$$hash?"#"+sb(this.$$hash):"";this.$$url=oc(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$rewrite=function(a){if(Wa(b)==Wa(a))return a}}function sc(b,a){this.$$html5=!0;Ib.apply(this,arguments);var c=Gb(b);this.$$rewrite=function(d){var e;if(b==Wa(d))return d; +if(e=na(c,d))return b+a+e;if(c===d+"/")return c}}function hb(b){return function(){return this[b]}}function tc(b,a){return function(c){if(H(c))return this[b];this[b]=a(c);this.$$compose();return this}}function ud(){var b="",a=!1;this.hashPrefix=function(a){return z(a)?(b=a,this):b};this.html5Mode=function(b){return z(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function f(a){c.$broadcast("$locationChangeSuccess",h.absUrl(),a)}var h,l=d.baseHref(), +k=d.url();a?(l=k.substring(0,k.indexOf("/",k.indexOf("//")+2))+(l||"/"),e=e.history?rc:sc):(l=Wa(k),e=Ib);h=new e(l,"#"+b);h.$$parse(h.$$rewrite(k));g.on("click",function(a){if(!a.ctrlKey&&!a.metaKey&&2!=a.which){for(var b=x(a.target);"a"!==v(b[0].nodeName);)if(b[0]===g[0]||!(b=b.parent())[0])return;var e=b.prop("href"),f=h.$$rewrite(e);e&&(!b.attr("target")&&f&&!a.isDefaultPrevented())&&(a.preventDefault(),f!=d.url()&&(h.$$parse(f),c.$apply(),W.angular["ff-684208-preventDefault"]=!0))}});h.absUrl()!= +k&&d.url(h.absUrl(),!0);d.onUrlChange(function(a){h.absUrl()!=a&&(c.$broadcast("$locationChangeStart",a,h.absUrl()).defaultPrevented?d.url(h.absUrl()):(c.$evalAsync(function(){var b=h.absUrl();h.$$parse(a);f(b)}),c.$$phase||c.$digest()))});var m=0;c.$watch(function(){var a=d.url(),b=h.$$replace;m&&a==h.absUrl()||(m++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",h.absUrl(),a).defaultPrevented?h.$$parse(a):(d.url(h.absUrl(),b),f(a))}));h.$$replace=!1;return m});return h}]}function vd(){var b= +!0,a=this;this.debugEnabled=function(a){return z(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||s;return e.apply?function(){var a=[];q(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"), +warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function pa(b,a){if("constructor"===b)throw za("isecfld",a);return b}function Xa(b,a){if(b){if(b.constructor===b)throw za("isecfn",a);if(b.document&&b.location&&b.alert&&b.setInterval)throw za("isecwindow",a);if(b.children&&(b.nodeName||b.on&&b.find))throw za("isecdom",a);}return b}function ib(b,a,c,d,e){e=e||{};a=a.split(".");for(var g,f=0;1e?uc(d[0],d[1],d[2],d[3],d[4],c,a):function(b,g){var f=0,h;do h=uc(d[f++],d[f++],d[f++],d[f++],d[f++],c,a)(b,g),g=r,b=h;while(fa)for(b in f++,d)d.hasOwnProperty(b)&&!e.hasOwnProperty(b)&&(m--,delete d[b])}else d!==e&&(d=e,f++);return f},function(){b(e,d,c)})},$digest:function(){var d, +f,g,h,k=this.$$asyncQueue,q=this.$$postDigestQueue,r,v,y=b,s,x=[],z,X,$;l("$digest");c=null;do{v=!1;for(s=this;k.length;){try{$=k.shift(),$.scope.$eval($.expression)}catch(O){n.$$phase=null,e(O)}c=null}a:do{if(h=s.$$watchers)for(r=h.length;r--;)try{if(d=h[r])if((f=d.get(s))!==(g=d.last)&&!(d.eq?ta(f,g):"number"==typeof f&&"number"==typeof g&&isNaN(f)&&isNaN(g)))v=!0,c=d,d.last=d.eq?ga(f):f,d.fn(f,g===m?f:g,s),5>y&&(z=4-y,x[z]||(x[z]=[]),X=A(d.exp)?"fn: "+(d.exp.name||d.exp.toString()):d.exp,X+="; newVal: "+ +oa(f)+"; oldVal: "+oa(g),x[z].push(X));else if(d===c){v=!1;break a}}catch(M){n.$$phase=null,e(M)}if(!(h=s.$$childHead||s!==this&&s.$$nextSibling))for(;s!==this&&!(h=s.$$nextSibling);)s=s.$parent}while(s=h);if(v&&!y--)throw n.$$phase=null,a("infdig",b,oa(x));}while(v||k.length);for(n.$$phase=null;q.length;)try{q.shift()()}catch(S){e(S)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this!==n&&(a.$$childHead==this&&(a.$$childHead=this.$$nextSibling), +a.$$childTail==this&&(a.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null)}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a){n.$$phase||n.$$asyncQueue.length||f.defer(function(){n.$$asyncQueue.length&&n.$digest()});this.$$asyncQueue.push({scope:this,expression:a})}, +$$postDigest:function(a){this.$$postDigestQueue.push(a)},$apply:function(a){try{return l("$apply"),this.$eval(a)}catch(b){e(b)}finally{n.$$phase=null;try{n.$digest()}catch(c){throw e(c),c;}}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[bb(c,b)]=null}},$emit:function(a,b){var c=[],d,f=this,g=!1,h={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},l=[h].concat(ua.call(arguments, +1)),k,m;do{d=f.$$listeners[a]||c;h.currentScope=f;k=0;for(m=d.length;kc.msieDocumentMode)throw ra("iequirks");var e= +ga(fa);e.isEnabled=function(){return b};e.trustAs=d.trustAs;e.getTrusted=d.getTrusted;e.valueOf=d.valueOf;b||(e.trustAs=e.getTrusted=function(a,b){return b},e.valueOf=Ba);e.parseAs=function(b,c){var d=a(c);return d.literal&&d.constant?d:function(a,c){return e.getTrusted(b,d(a,c))}};var g=e.parseAs,f=e.getTrusted,h=e.trustAs;q(fa,function(a,b){var c=v(b);e[Ra("parse_as_"+c)]=function(b){return g(a,b)};e[Ra("get_trusted_"+c)]=function(b){return f(a,b)};e[Ra("trust_as_"+c)]=function(b){return h(a,b)}}); +return e}]}function Ed(){this.$get=["$window","$document",function(b,a){var c={},d=R((/android (\d+)/.exec(v((b.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),g=a[0]||{},f=g.documentMode,h,l=/^(Moz|webkit|O|ms)(?=[A-Z])/,k=g.body&&g.body.style,m=!1,n=!1;if(k){for(var p in k)if(m=l.exec(p)){h=m[0];h=h.substr(0,1).toUpperCase()+h.substr(1);break}h||(h="WebkitOpacity"in k&&"webkit");m=!!("transition"in k||h+"Transition"in k);n=!!("animation"in k||h+"Animation"in k); +!d||m&&n||(m=D(g.body.style.webkitTransition),n=D(g.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hashchange:"onhashchange"in b&&(!f||7b;b=Math.abs(b);var f=b+"",h="",l=[],k=!1;if(-1!==f.indexOf("e")){var m=f.match(/([\d\.]+)e(-?)(\d+)/);m&&"-"==m[2]&&m[3]>e+1?f="0":(h=f,k=!0)}if(k)0b)&&(h=b.toFixed(e));else{f=(f.split(Fc)[1]||"").length;H(e)&&(e=Math.min(Math.max(a.minFrac,f),a.maxFrac));f=Math.pow(10,e);b=Math.round(b*f)/f;b=(""+b).split(Fc);f=b[0];b=b[1]||"";var m=0,n=a.lgSize,p=a.gSize;if(f.length>=n+p)for(m=f.length-n,k=0;kb&&(d="-",b=-b);for(b=""+b;b.length-c)e+=c;0===e&&-12==c&&(e=12);return Lb(e,a,d)}}function jb(b,a){return function(c, +d){var e=c["get"+b](),g=Ia(a?"SHORT"+b:b);return d[g][e]}}function Bc(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var g=0,f=0,h=b[8]?a.setUTCFullYear:a.setFullYear,l=b[8]?a.setUTCHours:a.setHours;b[9]&&(g=R(b[9]+b[10]),f=R(b[9]+b[11]));h.call(a,R(b[1]),R(b[2])-1,R(b[3]));g=R(b[4]||0)-g;f=R(b[5]||0)-f;h=R(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));l.call(a,g,f,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; +return function(c,e){var g="",f=[],h,l;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;D(c)&&(c=Md.test(c)?R(c):a(c));qb(c)&&(c=new Date(c));if(!La(c))return c;for(;e;)(l=Nd.exec(e))?(f=f.concat(ua.call(l,1)),e=f.pop()):(f.push(e),e=null);q(f,function(a){h=Od[a];g+=h?h(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Id(){return function(b){return oa(b,!0)}}function Jd(){return function(b,a){if(!L(b)&&!D(b))return b;a=R(a);if(D(b))return a?0<=a?b.slice(0,a):b.slice(a, +b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0a||37<=a&&40>=a)||k()});if(e.hasEvent("paste"))a.on("paste cut",k)}a.on("change",h);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)};var m=c.ngPattern,n=function(a,b){if(d.$isEmpty(b)||a.test(b))return d.$setValidity("pattern",!0),b;d.$setValidity("pattern",!1);return r};m&&((e=m.match(/^\/(.*)\/([gim]*)$/))?(m=RegExp(e[1], +e[2]),e=function(a){return n(m,a)}):e=function(c){var d=b.$eval(m);if(!d||!d.test)throw G("ngPattern")("noregexp",m,d,ha(a));return n(d,c)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var p=R(c.ngMinlength);e=function(a){if(!d.$isEmpty(a)&&a.lengtht)return d.$setValidity("maxlength", +!1),r;d.$setValidity("maxlength",!0);return a};d.$parsers.push(e);d.$formatters.push(e)}}function Mb(b,a){b="ngClass"+b;return function(){return{restrict:"AC",link:function(c,d,e){function g(b){if(!0===a||c.$index%2===a){var d=f(b||"");h?ta(b,h)||e.$updateClass(d,f(h)):e.$addClass(d)}h=ga(b)}function f(a){if(L(a))return a.join(" ");if(U(a)){var b=[];q(a,function(a,c){a&&b.push(c)});return b.join(" ")}return a}var h;c.$watch(e[b],g,!0);e.$observe("class",function(a){g(c.$eval(e[b]))});"ngClass"!== +b&&c.$watch("$index",function(d,g){var h=d&1;if(h!==g&1){var n=f(c.$eval(e[b]));h===a?e.$addClass(n):e.$removeClass(n)}})}}}}var v=function(b){return D(b)?b.toLowerCase():b},Ia=function(b){return D(b)?b.toUpperCase():b},E,x,Ca,ua=[].slice,Pd=[].push,$a=Object.prototype.toString,Na=G("ng"),Pa=W.angular||(W.angular={}),Va,Ga,ja=["0","0","0"];E=R((/msie (\d+)/.exec(v(navigator.userAgent))||[])[1]);isNaN(E)&&(E=R((/trident\/.*; rv:(\d+)/.exec(v(navigator.userAgent))||[])[1]));s.$inject=[];Ba.$inject= +[];var aa=function(){return String.prototype.trim?function(b){return D(b)?b.trim():b}:function(b){return D(b)?b.replace(/^\s\s*/,"").replace(/\s\s*$/,""):b}}();Ga=9>E?function(b){b=b.nodeName?b:b[0];return b.scopeName&&"HTML"!=b.scopeName?Ia(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var Tc=/[A-Z]/g,Qd={full:"1.2.5",major:1,minor:2,dot:5,codeName:"singularity-expansion"},Sa=I.cache={},db=I.expando="ng-"+(new Date).getTime(),Xc=1,Hc=W.document.addEventListener? +function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},Ab=W.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},Vc=/([\:\-\_]+(.))/g,Wc=/^moz([A-Z])/,xb=G("jqLite"),Fa=I.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===N.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),I(W).on("load",a))},toString:function(){var b=[];q(this,function(a){b.push(""+a)});return"["+b.join(", ")+ +"]"},eq:function(b){return 0<=b?x(this[b]):x(this[this.length+b])},length:0,push:Pd,sort:[].sort,splice:[].splice},fb={};q("multiple selected checked disabled readOnly required open".split(" "),function(b){fb[v(b)]=b});var ec={};q("input select option textarea button form details".split(" "),function(b){ec[Ia(b)]=!0});q({data:ac,inheritedData:eb,scope:function(b){return x(b).data("$scope")||eb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return x(b).data("$isolateScope")|| +x(b).data("$isolateScopeNoTemplate")},controller:bc,injector:function(b){return eb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Bb,css:function(b,a,c){a=Ra(a);if(z(c))b.style[a]=c;else{var d;8>=E&&(d=b.currentStyle&&b.currentStyle[a],""===d&&(d="auto"));d=d||b.style[a];8>=E&&(d=""===d?r:d);return d}},attr:function(b,a,c){var d=v(a);if(fb[d])if(z(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||s).specified? +d:r;else if(z(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?r:b},prop:function(b,a,c){if(z(c))b[a]=c;else return b[a]},text:function(){function b(b,d){var e=a[b.nodeType];if(H(d))return e?b[e]:"";b[e]=d}var a=[];9>E?(a[1]="innerText",a[3]="nodeValue"):a[1]=a[3]="textContent";b.$dv="";return b}(),val:function(b,a){if(H(a)){if("SELECT"===Ga(b)&&b.multiple){var c=[];q(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value= +a},html:function(b,a){if(H(a))return b.innerHTML;for(var c=0,d=b.childNodes;c":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<= +e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Ud={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},Kb=function(a){this.options=a};Kb.prototype={constructor:Kb,lex:function(a){this.text=a;this.index=0;this.ch=r;this.lastCh=":";this.tokens=[];var c;for(a=[];this.index=a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d= +d||this.index;c=z(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw za("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index","<=",">="))a=this.binaryFn(a,c.fn,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.fn,this.multiplicative());return a},multiplicative:function(){for(var a= +this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.fn,this.unary());return a},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(Ya.ZERO,a.fn,this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()):this.primary()},fieldAccess:function(a){var c=this,d=this.expect().text,e=vc(d,this.options,this.text);return w(function(c,d,h){return e(h||a(c,d),d)},{assign:function(e,f,h){return ib(a(e,h),d,f,c.text,c.options)}})},objectIndex:function(a){var c= +this,d=this.expression();this.consume("]");return w(function(e,g){var f=a(e,g),h=d(e,g),l;if(!f)return r;(f=Xa(f[h],c.text))&&(f.then&&c.options.unwrapPromises)&&(l=f,"$$v"in f||(l.$$v=r,l.then(function(a){l.$$v=a})),f=f.$$v);return f},{assign:function(e,g,f){var h=d(e,f);return Xa(a(e,f),c.text)[h]=g}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this;return function(g,f){for(var h=[],l=c?c(g,f): +g,k=0;ka.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=a?"+":"")+(Lb(Math[0< +a?"floor":"ceil"](a/60),2)+Lb(Math.abs(a%60),2))}},Nd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,Md=/^\-?\d+$/;Bc.$inject=["$locale"];var Kd=ca(v),Ld=ca(Ia);Dc.$inject=["$parse"];var Vd=ca({restrict:"E",compile:function(a,c){8>=E&&(c.href||c.name||c.$set("href",""),a.append(N.createComment("IE fix")));if(!c.href&&!c.name)return function(a,c){c.on("click",function(a){c.attr("href")||a.preventDefault()})}}}),Nb={};q(fb,function(a,c){if("multiple"!=a){var d=ma("ng-"+ +c);Nb[d]=function(){return{priority:100,compile:function(){return function(a,g,f){a.$watch(f[d],function(a){f.$set(c,!!a)})}}}}}});q(["src","srcset","href"],function(a){var c=ma("ng-"+a);Nb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),E&&e.prop(a,g[a]))})}}}});var mb={$addControl:s,$removeControl:s,$setValidity:s,$setDirty:s,$setPristine:s};Gc.$inject=["$element","$attrs","$scope"];var Ic=function(a){return["$timeout",function(c){return{name:"form", +restrict:a?"EAC":"E",controller:Gc,compile:function(){return{pre:function(a,e,g,f){if(!g.action){var h=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};Hc(e[0],"submit",h);e.on("$destroy",function(){c(function(){Ab(e[0],"submit",h)},0,!1)})}var l=e.parent().controller("form"),k=g.name||g.ngForm;k&&ib(a,k,f,k);if(l)e.on("$destroy",function(){l.$removeControl(f);k&&ib(a,k,r,k);w(f,mb)})}}}}}]},Wd=Ic(),Xd=Ic(!0),Yd=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/, +Zd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/,$d=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,Jc={text:ob,number:function(a,c,d,e,g,f){ob(a,c,d,e,g,f);e.$parsers.push(function(a){var c=e.$isEmpty(a);if(c||$d.test(a))return e.$setValidity("number",!0),""===a?null:c?a:parseFloat(a);e.$setValidity("number",!1);return r});e.$formatters.push(function(a){return e.$isEmpty(a)?"":""+a});d.min&&(a=function(a){var c=parseFloat(d.min);if(!e.$isEmpty(a)&&ac)return e.$setValidity("max",!1),r;e.$setValidity("max",!0);return a},e.$parsers.push(a),e.$formatters.push(a));e.$formatters.push(function(a){if(e.$isEmpty(a)||qb(a))return e.$setValidity("number",!0),a;e.$setValidity("number",!1);return r})},url:function(a,c,d,e,g,f){ob(a,c,d,e,g,f);a=function(a){if(e.$isEmpty(a)||Yd.test(a))return e.$setValidity("url",!0),a;e.$setValidity("url", +!1);return r};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,f){ob(a,c,d,e,g,f);a=function(a){if(e.$isEmpty(a)||Zd.test(a))return e.$setValidity("email",!0),a;e.$setValidity("email",!1);return r};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){H(d.name)&&c.attr("name",Za());c.on("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a, +c,d,e){var g=d.ngTrueValue,f=d.ngFalseValue;D(g)||(g=!0);D(f)||(f=!1);c.on("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return a!==g};e.$formatters.push(function(a){return a===g});e.$parsers.push(function(a){return a?g:f})},hidden:s,button:s,submit:s,reset:s},Kc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,f){f&&(Jc[v(g.type)]||Jc.text)(d,e,g,f,c,a)}}}], +lb="ng-valid",kb="ng-invalid",Ja="ng-pristine",nb="ng-dirty",ae=["$scope","$exceptionHandler","$attrs","$element","$parse",function(a,c,d,e,g){function f(a,c){c=c?"-"+cb(c,"-"):"";e.removeClass((a?kb:lb)+c).addClass((a?lb:kb)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var h=g(d.ngModel),l=h.assign;if(!l)throw G("ngModel")("nonassign",d.ngModel,ha(e)); +this.$render=s;this.$isEmpty=function(a){return H(a)||""===a||null===a||a!==a};var k=e.inheritedData("$formController")||mb,m=0,n=this.$error={};e.addClass(Ja);f(!0);this.$setValidity=function(a,c){n[a]!==!c&&(c?(n[a]&&m--,m||(f(!0),this.$valid=!0,this.$invalid=!1)):(f(!1),this.$invalid=!0,this.$valid=!1,m++),n[a]=!c,f(c,a),k.$setValidity(a,c,this))};this.$setPristine=function(){this.$dirty=!1;this.$pristine=!0;e.removeClass(nb).addClass(Ja)};this.$setViewValue=function(d){this.$viewValue=d;this.$pristine&& +(this.$dirty=!0,this.$pristine=!1,e.removeClass(Ja).addClass(nb),k.$setDirty());q(this.$parsers,function(a){d=a(d)});this.$modelValue!==d&&(this.$modelValue=d,l(a,d),q(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}}))};var p=this;a.$watch(function(){var c=h(a);if(p.$modelValue!==c){var d=p.$formatters,e=d.length;for(p.$modelValue=c;e--;)c=d[e](c);p.$viewValue!==c&&(p.$viewValue=c,p.$render())}return c})}],be=function(){return{require:["ngModel","^?form"],controller:ae,link:function(a, +c,d,e){var g=e[0],f=e[1]||mb;f.$addControl(g);a.$on("$destroy",function(){f.$removeControl(g)})}}},ce=ca({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),Lc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&e.$isEmpty(a))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);d.$observe("required",function(){g(e.$viewValue)})}}}}, +de=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){if(!H(a)){var c=[];a&&q(a.split(g),function(a){a&&c.push(aa(a))});return c}});e.$formatters.push(function(a){return L(a)?a.join(", "):r});e.$isEmpty=function(a){return!a||!a.length}}}},ee=/^(true|false|\d+)$/,fe=function(){return{priority:100,compile:function(a,c){return ee.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a, +c,g){a.$watch(g.ngValue,function(a){g.$set("value",a)})}}}},ge=sa(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==r?"":a)})}),he=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],ie=["$sce","$parse",function(a,c){return function(d,e,g){e.addClass("ng-binding").data("$binding",g.ngBindHtml);var f=c(g.ngBindHtml); +d.$watch(function(){return(f(d)||"").toString()},function(c){e.html(a.getTrustedHtml(f(d))||"")})}}],je=Mb("",!0),ke=Mb("Odd",0),le=Mb("Even",1),me=sa({compile:function(a,c){c.$set("ngCloak",r);a.removeClass("ng-cloak")}}),ne=[function(){return{scope:!0,controller:"@",priority:500}}],Mc={};q("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var c=ma("ng-"+a);Mc[c]=["$parse",function(d){return{compile:function(e, +g){var f=d(g[c]);return function(c,d,e){d.on(v(a),function(a){c.$apply(function(){f(c,{$event:a})})})}}}}]});var oe=["$animate",function(a){return{transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,g,f){var h,l;c.$watch(e.ngIf,function(g){Oa(g)?l||(l=c.$new(),f(l,function(c){c[c.length++]=N.createComment(" end ngIf: "+e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)})):(l&&(l.$destroy(),l=null),h&&(a.leave(vb(h.clone)),h=null))})}}}],pe=["$http","$templateCache", +"$anchorScroll","$animate","$sce",function(a,c,d,e,g){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:Pa.noop,compile:function(f,h){var l=h.ngInclude||h.src,k=h.onload||"",m=h.autoscroll;return function(f,h,q,r,B){var s=0,u,v,x=function(){u&&(u.$destroy(),u=null);v&&(e.leave(v),v=null)};f.$watch(g.parseAsResourceUrl(l),function(g){var l=function(){!z(m)||m&&!f.$eval(m)||d()},q=++s;g?(a.get(g,{cache:c}).success(function(a){if(q===s){var c=f.$new();r.template=a;a=B(c, +function(a){x();e.enter(a,null,h,l)});u=c;v=a;u.$emit("$includeContentLoaded");f.$eval(k)}}).error(function(){q===s&&x()}),f.$emit("$includeContentRequested")):(x(),r.template=null)})}}}}],qe=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(c,d,e,g){d.html(g.template);a(d.contents())(c)}}}],re=sa({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),se=sa({terminal:!0,priority:1E3}),te=["$locale","$interpolate",function(a,c){var d= +/{}/g;return{restrict:"EA",link:function(e,g,f){var h=f.count,l=f.$attr.when&&g.attr(f.$attr.when),k=f.offset||0,m=e.$eval(l)||{},n={},p=c.startSymbol(),t=c.endSymbol(),r=/^when(Minus)?(.+)$/;q(f,function(a,c){r.test(c)&&(m[v(c.replace("when","").replace("Minus","-"))]=g.attr(f.$attr[c]))});q(m,function(a,e){n[e]=c(a.replace(d,p+h+"-"+k+t))});e.$watch(function(){var c=parseFloat(e.$eval(h));if(isNaN(c))return"";c in m||(c=a.pluralCat(c-k));return n[c](e,g,!0)},function(a){g.text(a)})}}}],ue=["$parse", +"$animate",function(a,c){var d=G("ngRepeat");return{transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,link:function(e,g,f,h,l){var k=f.ngRepeat,m=k.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),n,p,t,r,s,v,u={$id:Ea};if(!m)throw d("iexp",k);f=m[1];h=m[2];(m=m[4])?(n=a(m),p=function(a,c,d){v&&(u[v]=a);u[s]=c;u.$index=d;return n(e,u)}):(t=function(a,c){return Ea(c)},r=function(a){return a});m=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!m)throw d("iidexp",f);s=m[3]|| +m[1];v=m[2];var z={};e.$watchCollection(h,function(a){var f,h,m=g[0],n,u={},H,O,M,S,D,w,G=[];if(pb(a))D=a,n=p||t;else{n=p||r;D=[];for(M in a)a.hasOwnProperty(M)&&"$"!=M.charAt(0)&&D.push(M);D.sort()}H=D.length;h=G.length=D.length;for(f=0;fJ;)x.pop().element.remove()}for(;y.length>A;)y.pop()[0].element.remove()}var k;if(!(k=s.match(d)))throw De("iexp", +s,ha(f));var l=c(k[2]||k[1]),m=k[4]||k[6],n=k[5],p=c(k[3]||""),q=c(k[2]?k[1]:m),t=c(k[7]),u=k[8]?c(k[8]):null,y=[[{element:f,label:""}]];w&&(a(w)(e),w.removeClass("ng-scope"),w.remove());f.empty();f.on("change",function(){e.$apply(function(){var a,c=t(e)||[],d={},h,k,l,p,s,x,w;if(v)for(k=[],p=0,x=y.length;p@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-start{border-spacing:1px 1px;-ms-zoom:1.0001;}.ng-animate-active{border-spacing:0px 0px;-ms-zoom:1;}'); +//# sourceMappingURL=angular.min.js.map diff --git a/InterfacesClasses2/classesObjectsMethodsObjectives.html b/InterfacesClasses2/classesObjectsMethodsObjectives.html new file mode 100644 index 0000000..6e0f5bd --- /dev/null +++ b/InterfacesClasses2/classesObjectsMethodsObjectives.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + Learning Objectives + + + + + + + + + + +
    +

    + Learning Objectives +

    +
    +

    + By the end of this lesson, you should be able to: +

    +
      +
    • + explain what we mean by classes, objects, fields, and methods +
    • +
    • + show how those ideas are expressed in the Java object system +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/concrete1.html b/InterfacesClasses2/concrete1.html new file mode 100644 index 0000000..b93059e --- /dev/null +++ b/InterfacesClasses2/concrete1.html @@ -0,0 +1,70 @@ + + + + + + + + + + + + Concrete Data Types + + + + + + + + + + +
    +

    + Concrete and Abstract Data Types +

    +
    +

    + A concrete data type is a data type + whose representation is known and relied upon + by the programmers who use the data type. +

    +

    + If you know the representation of a data type and are allowed + to rely upon that knowledge, then the data type is concrete. +

    +

    + If you do not know the representation of a data type + and are not allowed to rely upon its representation, + then the data type is abstract. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/concrete2.html b/InterfacesClasses2/concrete2.html new file mode 100644 index 0000000..5b82d20 --- /dev/null +++ b/InterfacesClasses2/concrete2.html @@ -0,0 +1,114 @@ + + + + + + + + + + + + Examples of Concrete and Abstract Data Types + + + + + + + + + + +
    +
    +

    + Examples of Concrete and Abstract Data Types: +

    +
      +
    • + The MouseEvent data type defined by Racket + is a concrete data type. +
      + You know its values are strings, + and you know the possible values of those strings + (such as "button-down"). + You are allowed to rely upon that representation when + you write functions that process a MouseEvent. +
      +
    • +
    • + The structure types you designed and defined + near the beginning of the semester + were concrete types. +
      + You knew the field names of each structure, + and you relied upon that knowledge in your observer templates + and in functions that used those observer templates. +
      +
    • +
    • + The char[] type of Java is concrete. +
      + You know the values of that type are represented as + 0-origin arrays of fixed length, + and you know every element of those arrays is + represented by a 16-bit integer. +
      +
    • +
    • + The List type of Java is abstract. +
      + You do not know how values of that type are represented. + A value of the List type might be + a LinkedList, + an ArrayList, + a CopyOnWriteArrayList, + or an object of some class defined by the course staff + whose representation will never be revealed to you. + Methods that are passed a List argument can + observe properties of that argument by calling the methods + listed by the List interface, + but they cannot rely on the representation of the + argument. +
      +
      + Note also that, in general, you do not even know whether + a value of the List type is mutable. + All of the methods listed by the List interface that + are capable of modifying a list's state are optional. + You cannot use optional methods unless a precondition + or some other invariant tells you the methods are available + for you to use. +
      +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/dontBreakAbstractionBarriers.html b/InterfacesClasses2/dontBreakAbstractionBarriers.html new file mode 100644 index 0000000..9f70d9b --- /dev/null +++ b/InterfacesClasses2/dontBreakAbstractionBarriers.html @@ -0,0 +1,97 @@ + + + + + + + + + + + + Don't Break the Abstraction Barrier + + + + + + + + + + +
    +

    + Don't Break the Abstraction Barrier +

    +
    +

    + Programming languages may also include special-purpose features + that allow debuggers and similar tools to work around + abstraction barriers that would otherwise be enforced + by the language. +

    +

    + Good programmers do not use those features to break + abstraction barriers. +

    +
    +

    + Java includes a few features that can be misused + to obtain knowledge of an abstract data type's + representation. + Inappropriate use of those features, which include + instanceof, getClass, and casts, + marks you as an inexperienced or weak programmer. +

    +

    + In this course, you should use instanceof + and casts only when writing an equals method + as shown in the next lesson. + You should never use getClass. +

    +

    + You should try to follow that rule outside of this course + as well. + If you find yourself resorting to features we forbid + in this course, you should ask yourself: +

    +
      +
    • + Am I doing this because I am not a good programmer? +
    • +
    • + Or am I doing this because the job I am doing forces + me to use a poorly designed data type? +
    • +
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality1.html b/InterfacesClasses2/equality1.html new file mode 100644 index 0000000..dce98ad --- /dev/null +++ b/InterfacesClasses2/equality1.html @@ -0,0 +1,65 @@ + + + + + + + + + + + + Equality + + + + + + + + + + +
    +

    + Equality +

    +
    +

    + This lesson considers the surprisingly subtle concept of equality. +

    +

    + It also discusses the equals(Object), + hashCode(), and toString() methods + of Java classes, and defines those methods for the UTC example + of a previous lesson. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality2.html b/InterfacesClasses2/equality2.html new file mode 100644 index 0000000..d77ad20 --- /dev/null +++ b/InterfacesClasses2/equality2.html @@ -0,0 +1,69 @@ + + + + + + + + + + + + Learning Objectives + + + + + + + + + + +
    +

    + Learning Objectives +

    +
    +

    + By the end of this lesson, you should be able to: +

    +
      +
    • + explain why we often need several different notions of equality +
    • +
    • + define equals(Object), + hashCode(), and toString() methods + for simple classes in Java. +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality3.html b/InterfacesClasses2/equality3.html new file mode 100644 index 0000000..9b8dd0e --- /dev/null +++ b/InterfacesClasses2/equality3.html @@ -0,0 +1,110 @@ + + + + + + + + + + + + Equality: What a Concept + + + + + + + + + + +
    +
    +

    + Equality: What a Concept +

    +

    + Equality sounds like a simple concept: + Two things are equal if and only if they're the same. +

    +

    + But what does it mean for two things to be the same? +

    +

    + Imagine yourself writing a string matching function + to be used in some search engine. + Which of the following strings should your function + regard as the same? +

    +
    +      Kurt Goedel
    +      kurt gödel
    +      KURT GÖDEL
    +      Kurt Gödel
    +      Kurt Gödel
    +
    +

    + For the purpose of matching strings in a search engine, + you might want to ignore the differences between upper + and lower case letters. +

    +

    + You almost certainly want to ignore the differences between + the last two strings above. + Chances are, you can't even see any difference between them. +

    +

    + The next-to-last string, "Kurt Gödel", is represented in + Unicode's normalization form NFC, and occupies 12 bytes + in the UTF-8 format used by this web page. +

    +

    + The last string, "Kurt Gödel", is represented in + Unicode's normalization form NFD, and occupies 13 bytes + in the UTF-8 format used by this web page. +

    +

    + To ignore case when comparing strings in Scheme or Java, + you can use the + string-ci=? function or + equalsIgnoreCase method instead of + string=? or + equals. +

    +

    + To compare strings while ignoring differences between the + various ways to represent a string in Unicode, you should + convert both strings to a common normalization form before + comparing them. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality4.html b/InterfacesClasses2/equality4.html new file mode 100644 index 0000000..cbcc722 --- /dev/null +++ b/InterfacesClasses2/equality4.html @@ -0,0 +1,75 @@ + + + + + + + + + + + + Different Notions of Equality + + + + + + + + + + +
    +
    +

    + Different Notions of Equality +

    +

    + As we have seen with strings, the notion of equality you + want to use depends on the situation. +

    +

    + When comparing identifiers in a case-sensitive programming language, + you want Kurt to be not equal to kurt. +

    +

    + When comparing search terms for a search engine, you probably + want Kurt to be equal to kurt. +

    +

    + As programmers, we often allow for different notions of + equality by writing functions and methods that accept the + desired notion of equality as an additional parameter. + For convenience, we may allow that parameter to be omitted, + in which case we use some default notion of equality. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality5.html b/InterfacesClasses2/equality5.html new file mode 100644 index 0000000..472b6a0 --- /dev/null +++ b/InterfacesClasses2/equality5.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + The equals(Object) Method in Java + + + + + + + + + + +
    +
    +

    + The equals(Object) Method in Java +

    +

    + In Java, the default notion of equality on objects is + defined by an equals method, which accepts + any Object as its argument and returns a + boolean indicating whether that object should be considered + equal to this object. +

    +

    + If you don't define an equals(Object) method + in a Java class, then it will inherit an equals + method from its superclass. +

    +

    + In the Java classes we have defined so far, we have not + specified a superclass. + When no superclass is specified, the superclass is Object. + When objects of a class are immutable, as has been true for + all of the classes we have defined so far, + the equals method that would + be inherited from the Object class is almost + certainly inappropriate. +

    +

    + That means we need to define an equals method + in our classes. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality6.html b/InterfacesClasses2/equality6.html new file mode 100644 index 0000000..1ccf2ff --- /dev/null +++ b/InterfacesClasses2/equality6.html @@ -0,0 +1,124 @@ + + + + + + + + + + + + Specification of the equals(Object) Method in Java + + + + + + + + + + +
    +
    +

    + Specification of the equals(Object) Method in Java +

    +

    + The specification of Java's standard libraries imposes + certain invariants that must be satisfied by any + equals(Object) method we define. +

    +
    +

    + The equals method implements an equivalence + relation on non-null object references: +

    +
      +
    • + It is reflexive: + for any non-null reference value x, + x.equals(x) should return true. +
    • +
    • + It is symmetric: + for any non-null reference values x and y, + x.equals(y) should return true if and only if + y.equals(x) returns true. +
    • +
    • + It is transitive: + for any non-null reference values + x, y, and z, + if x.equals(y) returns true and + y.equals(z) returns true, + then x.equals(z) should return true. +
    • +
    • + It is consistent: + for any non-null reference values x and y, + multiple invocations of + x.equals(y) consistently return true + or consistently return false, + provided no information used in equals comparisons + on the objects is modified. +
    • +
    • + For any non-null reference value x, + x.equals(null) should return false. +
    • +
    +
    +

    + The "provided no information...is modified" qualification + on the next-to-last invariant helps to explain why we have + been using immutable data types so far in this course. + With mutable data types, everything becomes more complicated. + In particular, x.equals(y) may return true + for one call but return false a moment later, + after some concurrent thread has changed the state of + x or y. +

    +

    + When we define an equals method, we must also + define a hashCode method: +

    +
    +

    + Note that it is generally necessary to override the + hashCode method whenever this method is overridden, + so as to maintain the general contract for the + hashCode method, which states that equal objects + must have equal hash codes. +

    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality7.html b/InterfacesClasses2/equality7.html new file mode 100644 index 0000000..2d1e756 --- /dev/null +++ b/InterfacesClasses2/equality7.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + Example: an equals Method for the UTC1 Class + + + + + + + + + + +
    +
    +

    + Example: an equals Method for the UTC1 Class +

    +

    + Within the + UTC1 class + of our example, we can define a suitable equals + method like this: +

    +
    +          public boolean equals (Object x) {
    +              if (x instanceof UTC) {
    +                  UTC t2 = (UTC) x;
    +                  return isEqual (t2);
    +              }
    +              else return false;
    +          }
    +
    +

    + The (x instanceof UTC) test determines whether + the object x is of a class that implements the + UTC interface. If so, then we can define an + alias t2 for x, + and use the isEqual method of the class + to determine whether x should be considered + equal to this UTC. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equality8.html b/InterfacesClasses2/equality8.html new file mode 100644 index 0000000..a9d1e85 --- /dev/null +++ b/InterfacesClasses2/equality8.html @@ -0,0 +1,116 @@ + + + + + + + + + + + + Casts + + + + + + + + + + +
    +
    +

    + Casts +

    +

    + The definition of t2 is rather interesting: +

    +
    +          public boolean equals (Object x) {
    +              if (x instanceof UTC) {
    +                  UTC t2 = (UTC) x;
    +                  return isEqual (t2);
    +              }
    +              else return false;
    +          }
    +
    +

    + That line defines a local variable named t2 whose + value is the same as the value of x. + Defining a second variable with the same value may seem pointless, + but it's convenient because the + type of the expression t2 is UTC, + whereas the type of the expression x is Object. + If we were to try to pass x as an argument to the + isEqual method, the Java compiler would report + a type error because the isEqual method only + accepts arguments of type UTC. +

    +

    + The right hand side of the variable declaration for t2 + casts x from type Object to + type UTC. + That cast is a type conversion. + It tells the Java compiler not to complain about the fact + that the type of x is different from UTC. +

    +
    +

    + In some unsafe programming languages, compilers just + trust the programmer and perform the type conversion + without checking to see whether the value of x + actually supports the operations listed in the UTC + interface. + If the programmer makes a mistake, the program will blow up + (if we're lucky) or generate incorrect results (if we're unlucky). + That's why programming languages in which compilers trust + the programmer's casts without checking are said to be unsafe. +

    +

    + In Java, C#, and other safe languages, compilers don't + just trust the programmer. Compilers generate code that + will check the value of x at run time to make sure + it is safe to use that value as though it were a UTC. + If that run-time check fails, it will throw an exception + that can be handled by an exception handler programmers + have written to deal with such mistakes. + At worst, if the programmers have not defined an exception handler, + a default exception handler will report the error, along with + information that will make it easier to fix the program, + and terminate the program in a clean manner. + That's part of why programming languages such as Java and C# + are said to be safe. +

    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equalityEtc1.html b/InterfacesClasses2/equalityEtc1.html new file mode 100644 index 0000000..4f8e8ea --- /dev/null +++ b/InterfacesClasses2/equalityEtc1.html @@ -0,0 +1,85 @@ + + + + + + + + + + + + Equality + + + + + + + + + + +
    +

    + Classes, Objects, and Interfaces in Java +

    +
    +

    + In this module, we will see how classes, objects, and interfaces + fit into our account of information analysis and data design. +

    +

    + We'll see how the functional and object-oriented paradigms + are related. +

    +

    + We'll learn how to apply the design recipe in an object-oriented + language. +

    +
    +
    + + Creative Commons License + + © Mitchell Wand, 2012-2015 +
    + This work is licensed under a + + Creative Commons Attribution-NonCommercial 4.0 International + License. + +
    + The work has been modified by William D Clinger in these ways + and more: + conversion from PowerPoint to HTML, and from Racket to Java. +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/equalityEtcSummary.html b/InterfacesClasses2/equalityEtcSummary.html new file mode 100644 index 0000000..f0ef69d --- /dev/null +++ b/InterfacesClasses2/equalityEtcSummary.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + Lesson Summary + + + + + + + + + + +
    +

    + Summary +

    +
    +

    + In this lesson, you've learned: +

    +
      +
    • + why we often need several different notions of equality +
    • +
    • + how to define an equals(Object) method +
    • +
    • + how to define a hashCode() method +
    • +
    • + how to define a toString() method +
    • +
    • + it will be easier to keep those methods consistent + across the various classes that implement an interface + if we use static methods and inheritance +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/hashcode1.html b/InterfacesClasses2/hashcode1.html new file mode 100644 index 0000000..1b548cd --- /dev/null +++ b/InterfacesClasses2/hashcode1.html @@ -0,0 +1,96 @@ + + + + + + + + + + + + The hashCode() Method in Java + + + + + + + + + + +
    +
    +

    + The hashCode() Method in Java +

    +

    + Java's specification of the hashCode() method + imposes the following invariant: +

    +
    +

    + If two objects are equal according to the + equals(Object) method, then calling the + hashCode method on each of the two objects + must produce the same integer result. +

    +
    +

    + That implies we must always always define a + hashCode method whenever we define an + equals method. +

    +

    + If the state of a mutable object changes in a way that + causes the object's equals method to return + false when compared to objects for which the method had + previously returned true, then the value returned by the + object's hashCode method is allowed to change + as well. Otherwise the value returned by the + hashCode method should remain the same for + all calls to hashCode. +

    +

    + The following definition is always a legal definition + of the hashCode method: +

    +
    +      public int hashCode () { return 0; }
    +
    +

    + Although legal, that definition defeats the purpose of the + hashCode method, which is to allow hash tables + to obtain an index that is likely to be different from the + indexes obtained for other objects. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/hashcode2.html b/InterfacesClasses2/hashcode2.html new file mode 100644 index 0000000..b3387a6 --- /dev/null +++ b/InterfacesClasses2/hashcode2.html @@ -0,0 +1,83 @@ + + + + + + + + + + + + Example: a hashCode Method for the UTC1 Class + + + + + + + + + + +
    +
    +

    + Example: a hashCode Method for the UTC1 Class +

    +

    + Within the + UTC1 class + of our example, we can define a suitable hashCode + method like this: +

    +
    +          public int hashCode () {
    +              return 100 * h + m;
    +          }
    +
    +

    + By itself, that definition does not guarantee that equal + UTC values will have equal hash codes, + because there might be other classes that implement the + UTC interface but define a hashCode + method that's incompatible with this one. +

    +

    + Defining compatible equals and hashCode + methods is hard enough within a single class, but it becomes + harder still when we have to maintain compatibility across + all of the classes that implement an interface. + In subsequent lessons, we will see how + static methods or inheritance can be used to make + that compatibility easier to maintain. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/specifyingADT1.html b/InterfacesClasses2/specifyingADT1.html new file mode 100644 index 0000000..644c652 --- /dev/null +++ b/InterfacesClasses2/specifyingADT1.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + Specifications for Abstract Data Types + + + + + + + + + + +
    +

    + Specifications for Abstract Data Types +

    +
    +

    + Abstract data types are specified by listing their + operations (functions and methods) + and by specifying the behaviors of those operations. +

    +

    + Java interfaces are examples of abstract data types. + The specifications of Java interfaces, + as found within + official documentation for the + java.util package, + shows how an abstract data type can be specified + without revealing its representation. +

    +

    + In general, an abstract data type is specified by + explaining how the operations that create values + of the type interact with operations that reveal + properties of those values or change the state of + those values (if the values are mutable). +

    +
    +

    + In some of your problem sets, you have seen how + abstract data types are specified by explaining + the desired combined behavior + of functions that create values with functions + that observe properties of those values. +

    +

    + For example: +

    +
    +        ;;; lit : Real -> Literal
    +        ;;; GIVEN: a real number
    +        ;;; RETURNS: a literal that represents that number
    +        ;;; EXAMPLE: (see the example given for literal-value,
    +        ;;;          which shows the desired combined behavior
    +        ;;;          of lit and literal-value)
    +        
    +        ;;; literal-value : Literal -> Real
    +        ;;; GIVEN: a literal
    +        ;;; RETURNS: the number it represents
    +        ;;; EXAMPLE: (literal-value (lit 17.4)) => 17.4
    +
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticAlgorithms1.html b/InterfacesClasses2/staticAlgorithms1.html new file mode 100644 index 0000000..463edf5 --- /dev/null +++ b/InterfacesClasses2/staticAlgorithms1.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + Algorithms can be Static Methods + + + + + + + + + + +
    +
    +

    + Algorithms can be Static Methods +

    +

    + Algorithms can often be implemented by static methods, + and this is especially useful when many different classes + implement the same interface. + Defining the algorithm's methods in each of those classes + would be tedious, and would also + violate the principle of Don't Repeat Yourself. +

    +

    + Consider, for example, an algorithm for sorting lists. + Java's standard libraries define at least 10 classes + that implement the List interface, + and application programs often define still more classes + that implement List. + Defining a separate sort method in all of those classes + would be silly. +

    +

    + Inheritance wouldn't solve the problem either, because + requiring every class that implements List + to inherit from one common superclass would interfere + with the use of inheritance to accomplish other goals. +

    +

    + List sorting algorithms should be representation independent: + They should work with any class that implements the + List interface. + That means we should be able to define a static sort + method that works with any List. +

    +

    + We don't have to do that ourselves, because Java's + standard libraries have already done that for us. + The java.util.Collections class +

    +
    +

    + consists exclusively of static methods that operate on or return + collections. It contains polymorphic algorithms that operate on + collections, "wrappers", which return a new collection backed by + a specified collection, and a few other odds and ends. +

    +
    +

    + In Java, the List interface extends the + Collection interface, so every List + is also a Collection. + It is considered good programming practice to define the + representation-independent static methods that operate on + all values of some interface type in a single class + whose name is the plural of the name of the interface. + Collections, for example is the class that + defines static methods that operate on or return + a Collection. +

    +

    + For our UTC example, therefore, we should + consider defining a UTCs class that contains + static methods that operate on values of the UTC + abstract data type. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticAlgorithms2.html b/InterfacesClasses2/staticAlgorithms2.html new file mode 100644 index 0000000..aa0c3bd --- /dev/null +++ b/InterfacesClasses2/staticAlgorithms2.html @@ -0,0 +1,109 @@ + + + + + + + + + + + + Example: UTCs + + + + + + + + + + +
    +
    +

    + Example: UTCs +

    +
    +      // The UTCs class defines static methods for the UTC type.
    +      
    +      public class UTCs {
    +      
    +          // Dynamic isEqual methods should delegate to this static method.
    +      
    +          public static boolean isEqual (UTC t1, UTC t2) {
    +              return (t1.hour() == t2.hour()) && (t1.minute() == t2.minute());
    +          }
    +      
    +          // Dynamic hashCode methods should delegate to this static method.
    +      
    +          public static int hashCode (UTC t) {
    +              return 100 * t.hour() + t.minute();
    +          }
    +      
    +          ...
    +      }
    +
    +

    + Having defined the UTCs class with static + isEqual(UTC,UTC) and hashCode(UTC) methods, + we can rewrite the + dynamic isEqual(UTC) and hashCode() methods + of our UTC1 class to delegate to that static method: +

    +
    +      class UTC1 implements UTC {
    +      
    +          ...
    +      
    +          // Returns true iff the given UTC is equal to this UTC.
    +      
    +          public boolean isEqual (UTC t2) {
    +              return UTCs.isEqual (this, t2);
    +          }
    +      
    +          ...
    +          public int hashCode () {
    +              return UTCs.hashCode (this);
    +          }
    +      
    +          ...
    +      }
    +
    +

    + That may look silly for such a simple example, but it will + become important when we define more classes that implement + the UTC interface, and would be even more + important when implementing abstract data types for which + equality testing and hash computation are more complicated. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticFactoryMethods1.html b/InterfacesClasses2/staticFactoryMethods1.html new file mode 100644 index 0000000..3f5590d --- /dev/null +++ b/InterfacesClasses2/staticFactoryMethods1.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + Static Factory Method Pattern + + + + + + + + + + +
    +
    +

    + Static Factory Method Pattern +

    +

    + Although Java's new C(...) syntax for creating + new objects is straightforward, it causes + problems when used indiscriminately in large programs. +

    +

    + In Java, that syntax requires + the creating method to know the name of the class for that + new object. + That may sound reasonable for simple data types such as + UTC, but what if there are two or more classes + that implement the UTC interface? + What if choosing which class to use is complicated? +

    +

    + One of the classes that implements the UTC + interface might be preferred during the early phases of + a program's execution, but a different representation + might be preferred during later phases. + If users of the UTC abstract data type + create new values of that type using the + new operator, then every use + of that operator would need to be augmented by conditional + code that determines the current phase of the program + before deciding whether to create the new value via + new UTC1(...) or new UTC2(...). +

    +

    + To give another example, suppose it becomes necessary to + improve the efficiency of a program, and someone concludes + its efficiency could be improved by creating at most one + UTC object for any given combination of hour + and minute. Then every occurrence of new UTC1(h,m) + would have to be replaced by a fairly complicated computation + that determines whether a UTC with hour and + minute components equal to h and m + is already available. If so, it would use that previously created + UTC. If not, it would create a new UTC + and enter that new UTC into a database of + available UTC values. +

    +

    + The computations implied by those two examples are too + complicated to be written out in full everywhere a new + UTC value is needed. + Writing those computations out in many different places + would violate the programming principle that says + Don't repeat yourself. +

    +

    + Static factory methods solve the problem. + Instead of writing out the logic needed to decide + whether it is necessary to create a brand new object, + and to decide which representation to use for that object + if a new object is needed, + we can define a single static factory method that + encapsulates the necessary logic. Everyone who needs to + create new values of that data type can then call the + static factory method instead of writing code that + contains explicit uses of the new syntax. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticFactoryMethods2.html b/InterfacesClasses2/staticFactoryMethods2.html new file mode 100644 index 0000000..287179b --- /dev/null +++ b/InterfacesClasses2/staticFactoryMethods2.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + Static Factory Method Pattern + + + + + + + + + + +
    +
    +

    + Static Factory Method Pattern +

    +

    + For our UTC example, we have already seen + some advantages to defining a UTCs class + that contains static methods for the UTC + type. + It is considered good programming practice to place + static factory methods for an interface type in a class + whose name is formed by taking the plural of the name of + the interface type. +

    +

    + So let's do it: +

    +
    +      public class UTCs {
    +      
    +          ...
    +      
    +          // static factory method for creating a UTC
    +          // GIVEN: the hour in [0,23] and the minute in [0,59]
    +          // RETURNS: a UTC with that hour and minute
    +      
    +          public static UTC make (int h, int m) {
    +              return new UTC1 (h, m);
    +          }
    +      
    +          ...
    +      }
    +
    +

    + Instead of writing +

    +
    +          new UTC1 (h, m)
    +
    +

    + users of the UTC data type should write +

    +
    +          UTCs.make (h, m)
    +
    +

    + That may look silly now, but it allows us to add arbitrarily + complicated logic as the program evolves. + To add that logic, we would modify the static factory method. + We won't have to modify any of the places where the factory + method is called. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticFactoryMethods3.html b/InterfacesClasses2/staticFactoryMethods3.html new file mode 100644 index 0000000..b9abd9b --- /dev/null +++ b/InterfacesClasses2/staticFactoryMethods3.html @@ -0,0 +1,99 @@ + + + + + + + + + + + + Static Factory Method Pattern + + + + + + + + + + +
    +
    +

    + Static Factory Method Pattern +

    +

    + In your programming assignments, you may have seen how + multiple representations of an abstract data type + help you to detect and to debug violations of the + ADT's abstraction barrier. +

    +

    + Changing the static factory method to choose randomly between + two different representations is therefore + a useful debugging technique: +

    +
    +      import java.util.Random;
    +      
    +      // The UTCs class defines static methods for the UTC type.
    +      // In particular, it defines a static factory method for creating
    +      // values of the UTC type.
    +      
    +      public class UTCs {
    +      
    +          ...
    +      
    +          // random number generator, to be used as a coin flip
    +      
    +          private static Random coinFlips = new Random();
    +      
    +          // static factory method for creating a UTC
    +          // GIVEN: the hour in [0,23] and the minute in [0,59]
    +          // RETURNS: a UTC with that hour and minute
    +      
    +          public static UTC make (int h, int m) {
    +              // flips a coin to decide whether to return an object
    +              // of class UTC1 or UTC2
    +      
    +              if (coinFlips.nextBoolean())
    +                  return new UTC1 (h, m);
    +              else
    +                  return new UTC2 (h, m);
    +          }
    +      
    +          ...
    +      }
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticFactoryMethods4.html b/InterfacesClasses2/staticFactoryMethods4.html new file mode 100644 index 0000000..b61316b --- /dev/null +++ b/InterfacesClasses2/staticFactoryMethods4.html @@ -0,0 +1,128 @@ + + + + + + + + + + + + Representation Independence + + + + + + + + + + +
    +
    +

    + Representation Independence +

    +

    + Factory methods improve the representation independence + of a program. +

    +

    + Here, for example, is a second representation for the + UTC ADT: +

    +
    +      // Constructor template for UTC2:
    +      //     new UTC2 (h, m)
    +      // Interpretation:
    +      //     h is the UTC hour (between 0 and 23, inclusive)
    +      //     m is the UTC minute (between 0 and 59, inclusive)
    +      // Representation:
    +      //     Internally, the hour is represented in Eastern Standard Time,
    +      //     which is five hours behind UTC.
    +      
    +      class UTC2 implements UTC {
    +      
    +          int h;    // the hour in EST, limited to [0,23]
    +          int m;    // the minute, limited to [0,59]
    +      
    +          // the Java constructor
    +      
    +          UTC2 (int h, int m) {
    +              this.h = (h >= 5) ? (h - 5) : h + 19;
    +              this.m = m;
    +          }
    +      
    +          // public methods
    +      
    +          // Returns the hour, between 0 and 23 inclusive.
    +      
    +          public int hour () {
    +              if (h < 19)
    +      	    return h + 5;
    +              else
    +                  return h - 19;
    +          }
    +      
    +          // Returns the minute, between 0 and 59 inclusive.
    +      
    +          public int minute () { return m; }
    +      
    +          // Returns true iff the given UTC is equal to this UTC.
    +      
    +          public boolean isEqual (UTC t2) {
    +              return UTCs.isEqual (this, t2);
    +          }
    +      
    +          // public methods that override methods inherited from Object
    +      
    +          public boolean equals (Object x) {
    +              if (x instanceof UTC) {
    +                  UTC t2 = (UTC) x;
    +                  return isEqual (t2);
    +              }
    +              else return false;
    +          }
    +      
    +          public int hashCode () {
    +              return UTCs.hashCode (this);
    +          }
    +      
    +          public String toString () {
    +              return UTCs.toString(this);
    +          }
    +      
    +          ...
    +      }
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticFactoryMethods5.html b/InterfacesClasses2/staticFactoryMethods5.html new file mode 100644 index 0000000..4c093f7 --- /dev/null +++ b/InterfacesClasses2/staticFactoryMethods5.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + Representation Independence + + + + + + + + + + +
    +
    +

    + Representation Independence +

    +

    + We have now defined two distinct representations for the + UTC abstract data type: + UTC1 and UTC2. +

    +

    + So long as a program respects the abstraction barrier of + the ADT, it won't matter which representation we use. + We can even use multiple representations in the same + program, and everything will still work just fine. +

    +

    + Representation independence allows us to improve our + representations as a program evolves, and it also allows + us to use multiple representations within a single program, + with each representation specialized to perform well under + the circumstances in which it will be used. +

    +

    + Representation independence is therefore an important aid + to writing efficient programs. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethods1.html b/InterfacesClasses2/staticMethods1.html new file mode 100644 index 0000000..0469ebd --- /dev/null +++ b/InterfacesClasses2/staticMethods1.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + Static Methods + + + + + + + + + + +
    +

    + Static Methods +

    +
    +

    + This lesson introduces static methods in Java and similar languages. +

    +

    + The methods we have seen in previous lessons are associated + with objects, and are called dynamic methods. +

    +

    + Static methods are not associated with objects. + In Java, static methods are associated with classes. + Static methods are just functions that happen to be + defined within a class instead of being defined at + the top level of a file as in Racket's + Intermediate Student Language. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethods2.html b/InterfacesClasses2/staticMethods2.html new file mode 100644 index 0000000..2cb57a2 --- /dev/null +++ b/InterfacesClasses2/staticMethods2.html @@ -0,0 +1,77 @@ + + + + + + + + + + + + Learning Objectives + + + + + + + + + + +
    +

    + Learning Objectives +

    +
    +

    + By the end of this lesson, you should be able to: +

    +
      +
    • + distinguish between static and dynamic methods +
    • +
    • + write a public static void main (String[]) method +
    • +
    • + use the Static Factory Method pattern +
    • +
    • + write static factory methods for your abstract data types +
    • +
    • + write static methods with parametric polymorphism in one or more + type parameters +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethods3.html b/InterfacesClasses2/staticMethods3.html new file mode 100644 index 0000000..1c6621b --- /dev/null +++ b/InterfacesClasses2/staticMethods3.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + Syntax of Dynamic and Static Method Calls + + + + + + + + + + +
    +
    +

    + Syntax of Dynamic and Static Method Calls +

    +

    + In Java, the f method of an object x + is called using this syntax: +

    +
    +      x.f(...)
    +
    +

    + And so, inside a dynamic method's definition, + the f method of this object's class + can be called as follows: +

    +
    +      this.f(...)
    +
    +

    + That is often abbreviated as: +

    +
    +      f(...)
    +
    +
    +

    + If g is a static method defined inside + a class named Class1, then g is + called using the following syntax: +

    +
    +      Class1.g(...)
    +
    +

    + Inside the definition of a static method, + references to this are forbidden because + they don't make sense. Static methods are associated + with classes, not objects, so there is no object for + this to denote. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethods4.html b/InterfacesClasses2/staticMethods4.html new file mode 100644 index 0000000..02ebbf4 --- /dev/null +++ b/InterfacesClasses2/staticMethods4.html @@ -0,0 +1,77 @@ + + + + + + + + + + + + Compiling and Running a Java Program + + + + + + + + + + +
    +
    +

    + Compiling and Running a Java Program +

    +

    + To compile and run a Java program, we can open a + Unix/Linux shell, MacOSX Terminal, or Windows CMD window, + cd to the directory that contains the program's + Java source code, and say +

    +
    +      javac *.java
    +
    +

    + To run the program we've just compiled, + we invoke the Java Virtual Machine (JVM) + by saying something like +

    +
    +      java Class1
    +
    +

    + where Class1 is the name of a public class + defined at the beginning of a file named Class1.java +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethods5.html b/InterfacesClasses2/staticMethods5.html new file mode 100644 index 0000000..fd1675e --- /dev/null +++ b/InterfacesClasses2/staticMethods5.html @@ -0,0 +1,91 @@ + + + + + + + + + + + + Why We Need Static Methods + + + + + + + + + + +
    +
    +

    + Why We Need Static Methods +

    +

    + Before we can call a dynamic method using the + x.f(...) syntax, + we have to create the object x + that will act as receiver for the call. +

    +

    + When a Java program first begins to execute, + before any objects have been created, + there are no objects that could act as receiver + for a dynamic method call. +

    +

    + To create the first objects, we have to call + at least one static method. +

    +

    + In Java, the first method called is the static method + named main that is defined in the class + we named on the command line that invoked the JVM. +

    +

    + If we invoke the JVM by saying java Class1, + then the JVM starts the program by calling the + static main method defined in class Class1. + If we invoke the JVM by saying java Foo, + then the JVM starts the program by calling the + static main method defined in class Foo. +

    +

    + A Java program can therefore have multiple main entry points, + each defined in a separate class. + As will be explained in the next lesson, + multiple entry points are convenient for unit testing. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethods6.html b/InterfacesClasses2/staticMethods6.html new file mode 100644 index 0000000..ff0cb64 --- /dev/null +++ b/InterfacesClasses2/staticMethods6.html @@ -0,0 +1,108 @@ + + + + + + + + + + + + Syntax of a main Method + + + + + + + + + + +
    +
    +

    + Syntax of a main Method +

    +

    + Each entry point of a Java program should be defined + as follows: +

    +
    +          public static void main (String[] args) {
    +              ...
    +          }
    +
    +

    + The argument passed to main, + conventionally called args, + is an array of strings representing the + arguments that were passed to the program + on the command line. + Those arguments provide a convenient way to supply simple inputs + to a Java program. +

    +

    + Example: + Suppose we run a Java program by saying +

    +
    +      java Class1 20 hello there
    +
    +

    + Then the args array passed to the + static main method of class Class1 + will be of length 3, and its elements will be the strings + "20" "hello" "there". +

    +

    + Example: + The following main method just prints its + command-line arguments and then exits: +

    +
    +          public static void main (String[] args) {
    +              for (String arg : args) {
    +                  System.out.println (arg);
    +              }
    +          }
    +
    +

    + (The for syntax of that example is called + a for-each loop because it was inspired by the + for-each procedure of Scheme, + which is similar to Scheme's map function + except it doesn't return a useful result. + Java's for-each loops are useful only when + their bodies have a side effect (such as printing). +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethodsPolymorphism1.html b/InterfacesClasses2/staticMethodsPolymorphism1.html new file mode 100644 index 0000000..1206aa9 --- /dev/null +++ b/InterfacesClasses2/staticMethodsPolymorphism1.html @@ -0,0 +1,100 @@ + + + + + + + + + + + + Parametric Polymorphism in Static Methods + + + + + + + + + + +
    +
    +

    + Parametric Polymorphism in Static Methods +

    +

    + The types used by a static method can include type parameters, + just as with dynamic methods. +

    +

    + With dynamic methods, however, the type parameters are within + the scope of type parameters declared for the class. + Within a IMap<K,V> class, for example, + dynamic methods can use type parameters K and V. +

    +

    + In Java, the type parameters declared with the class name + are actually associated with objects, not with the class. + (That allows different objects of the class to have different + types for the type parameters.) +

    +

    + Because the type parameters declared with the class name + are associated with objects, the class's static methods + are not within the scope of those type parameters. + If a static method refers to type parameters that do not + occur within the types of its arguments, those type parameters + must be declared by naming them within angle brackets + immediately before the return type of the static method. +

    +

    + Example. + The following static factory might be defined within an + IMaps<K,V> class associated with an + IMap<K,V> type of immutable finite + functions: +

    +
    +          public static <K,V> IMap<K,V> empty () { ... }
    +
    +

    + If the <K,V> declaration that comes + after static is omitted, the Java compiler + is likely to generate an error message that is hard to + understand. + If you are writing a polymorphic static method and get + an error message you don't understand, this is one of + the things you should check. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/staticMethodsSummary.html b/InterfacesClasses2/staticMethodsSummary.html new file mode 100644 index 0000000..6c6a775 --- /dev/null +++ b/InterfacesClasses2/staticMethodsSummary.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + Summary + + + + + + + + + + +
    +
    +

    + Summary +

    +
      +
    • + Dynamic methods are associated with objects. +
        +
      • + So this makes sense. +
      • +
      +
    • +
    • + Static methods are associated with classes. +
        +
      • + So this doesn't make sense. +
      • +
      +
    • +
    • + In Java, main methods are static. +
    • +
    • + Static methods can reduce duplication of code, + and can help with maintaining compatibility between + different classes that implement the same data type. +
    • +
    • + Static factory methods reduce duplication of code + and improve representation independence. +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects1.html b/InterfacesClasses2/testingObjects1.html new file mode 100644 index 0000000..f1c5e09 --- /dev/null +++ b/InterfacesClasses2/testingObjects1.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + Testing Simple Objects + + + + + + + + + + +
    +

    + Testing Simple Objects +

    +
    +

    + This lesson warns against some mistakes you can make + when testing objects, and suggests techniques you can + use for testing simple abstract data types and algorithms + in Java. +

    +

    + To keep things as simple as possible, this lesson does + not discuss the use of testing frameworks such as + + JUnit. + +

    +
    +
    + + Creative Commons License + + © Mitchell Wand, 2012-2015 +
    + This work is licensed under a + + Creative Commons Attribution-NonCommercial 4.0 International + License. + +
    + The work has been modified by William D Clinger in these ways + and more: + conversion from PowerPoint to HTML, and from Racket to Java. +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects11.html b/InterfacesClasses2/testingObjects11.html new file mode 100644 index 0000000..182185c --- /dev/null +++ b/InterfacesClasses2/testingObjects11.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + Testing Across Classes is Hard + + + + + + + + + + +
    +
    +

    + Testing Across Classes is Hard +

    +

    + Testing across multiple classes that implement the same + interface is hard to do well. +

    +

    + For one thing, the tests have to know all of the classes + that implement the interface. For black-box testing, + knowing all classes is generally impossible. +

    +

    + For another thing, more classes that implement the interface + might be added over time as the program evolves. + It's hard to keep the tests in sync with the program. +

    +

    + If the tested classes are designed to be extended using + inheritance, testing all classes that implement the + interface entails testing all subclasses as well. + That, too, is generally impossible to accomplish with + black-box testing, and it's especially hard to keep the + tests in sync with the program as new subclasses come and + go due to refactoring. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects2.html b/InterfacesClasses2/testingObjects2.html new file mode 100644 index 0000000..96effb9 --- /dev/null +++ b/InterfacesClasses2/testingObjects2.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + Learning Objectives + + + + + + + + + + +
    +

    + Learning Objectives +

    +
    +

    + By the end of this lesson, you should be able to: +

    +
      +
    • + write tests for the Java code you will write in this course +
    • +
    • + write tests that compare objects without breaking + their abstraction barriers +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects3.html b/InterfacesClasses2/testingObjects3.html new file mode 100644 index 0000000..f099b36 --- /dev/null +++ b/InterfacesClasses2/testingObjects3.html @@ -0,0 +1,91 @@ + + + + + + + + + + + + Unit Tests + + + + + + + + + + +
    +
    +

    + Unit Tests +

    +

    + In Java, it is often convenient to arrange for unit testing + of a class to be performed by a main method + defined in that class. +

    +

    + For example: +

    +
    +      class UTC1 implements UTC {
    +      
    +          ...
    +      
    +          // a main method for unit testing
    +      
    +          public static void main (String[] args) {
    +              UTC1tests.main(args);
    +          }
    +      }
    +
    +

    + In that example, the main method of UTC1 + just calls the main method of UTC1tests. + The UTC1tests class can be defined in the same file + as UTC1, or it can be defined in a separate file. +

    +

    + If the UTC1 class is defined in a file named + UTC1.java, that class can be compiled and tested + as follows: +

    +
    +      javac UTC1.java
    +      java UTC1
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects4.html b/InterfacesClasses2/testingObjects4.html new file mode 100644 index 0000000..1eb560a --- /dev/null +++ b/InterfacesClasses2/testingObjects4.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + Example: Unit Tests + + + + + + + + + + +
    +
    +

    + Example: Unit Tests +

    +

    + The main method below uses Java's assert + syntax to test UTC objects of class UTC1. +

    +
    +      // Unit tests for UTC1.
    +      
    +      class UTC1tests {
    +      
    +          public static void main (String[] args) {
    +              UTC t1 = new UTC1 (15, 31);
    +              UTC t2 = new UTC1 (14, 31);
    +              UTC t3 = new UTC1 (15, 32);
    +              UTC t4 = new UTC1 (15, 31);
    +      
    +              assert t1.hour() == 15 : "wrong hour for t1";
    +              assert t1.minute() == 31 : "wrong minute for t1";
    +      
    +              assert t1.isEqual (t1) : "isEqual says this doesn't equal this";
    +              assert t1.isEqual (t4) : "isEqual says this doesn't equal that";
    +              assert ! (t1.isEqual (t2)) : "isEqual true but hour different";
    +              assert ! (t1.isEqual (t3)) : "isEqual true but minute different";
    +      
    +              System.out.println ("All unit tests of UTC1 passed.");
    +          }
    +      }
    +
    +

    + As with the check-equal? function we've been using + in Racket, the error messages can be omitted; if that is done, + the colon must be omitted as well. +

    +

    + There might be other classes that implement the UTC + interface. The tests shown above do not test UTC + objects of any classes other than UTC1. +

    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects5.html b/InterfacesClasses2/testingObjects5.html new file mode 100644 index 0000000..ff890c0 --- /dev/null +++ b/InterfacesClasses2/testingObjects5.html @@ -0,0 +1,92 @@ + + + + + + + + + + + + Testing Across Classes + + + + + + + + + + +
    +
    +

    + Testing Across Classes +

    +

    + When more than one class implements an interface, + it is necessary to test objects of different classes. + Are they interchangeable? Do they interoperate correctly? +

    +

    + When testing objects of multiple classes that implement + an interface, it is often convenient to define a + main method in the class that defines + static methods for the data type specified by the + interface. +

    +
    +      // The UTCs class defines static methods for the UTC type.
    +      
    +      public class UTCs {
    +      
    +          ...
    +      
    +          // main method for testing
    +      
    +          public static void main (String[] args) {
    +              UTCsTests.main (args);
    +          }
    +      }
    +      
    +      // Tests for UTC objects created by the static factory method in UTCs.
    +      
    +      class UTCsTests {
    +      
    +          public static void main (String[] args) {
    +              ...
    +              System.out.println ("UTCs tests passed.");
    +          }
    +      }
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects6.html b/InterfacesClasses2/testingObjects6.html new file mode 100644 index 0000000..93361c4 --- /dev/null +++ b/InterfacesClasses2/testingObjects6.html @@ -0,0 +1,92 @@ + + + + + + + + + + + + Testing Across Classes + + + + + + + + + + +
    +
    +

    + Testing Across Classes +

    +

    + In the following example, testing across classes is + achieved because the static factory method, + UTCs.make, randomly chooses between + multiple classes that implement the UTC + interface. +

    +
    +      // Tests for UTC objects created by the static factory method in UTCs.
    +      
    +      class UTCsTests {
    +      
    +          public static void main (String[] args) {
    +      
    +              // We'll do these tests several times, to increase the
    +              // probability that objects of different classes will be created.
    +      
    +              int NTESTS = 5;    // how many times we'll run each test
    +      
    +              for (int i = 0; i < NTESTS; i = i + 1) {
    +                  UTC t0000 = UTCs.make (0, 0);      // always test boundary cases
    +                  UTC t0059 = UTCs.make (0, 59);
    +                  UTC t2300 = UTCs.make (23, 0);
    +                  UTC t2359 = UTCs.make (23, 59);
    +                  UTC t1531 = UTCs.make (15, 31);    // and test typical cases
    +      
    +                  assert t0000.hour() == 0    : "wrong hour for t0000";
    +                  assert t0000.minute() == 0  : "wrong minute for t0000";
    +                  assert t0059.hour() == 0    : "wrong hour for t0059";
    +                  assert t0059.minute() == 59 : "wrong minute for t0059";
    +                  ...
    +              }
    +              System.out.println ("UTCs tests passed.");
    +          }
    +      }
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjects7.html b/InterfacesClasses2/testingObjects7.html new file mode 100644 index 0000000..8b8f004 --- /dev/null +++ b/InterfacesClasses2/testingObjects7.html @@ -0,0 +1,106 @@ + + + + + + + + + + + + Testing the Usual Triumvirate + + + + + + + + + + +
    +
    +

    + Testing the Usual Triumvirate +

    +

    + In Java, we need to test the + equals(Object), + hashCode(), and + toString() methods. +

    +

    + These methods should behave consistently across all classes + that implement an interface, but that consistency is often + hard to achieve. + When something is hard to do correctly, it is especially + important to write tests for it. +

    +
    +      // Tests for UTC objects created by the static factory method in UTCs.
    +      
    +      class UTCsTests {
    +      
    +          public static void main (String[] args) {
    +      
    +              // We'll do these tests several times, to increase the
    +              // probability that objects of different classes will be created.
    +      
    +              int NTESTS = 5;    // how many times we'll run each test
    +      
    +              for (int i = 0; i < NTESTS; i = i + 1) {
    +                  ...
    +                  // tests of the usual triumvirate
    +      
    +                  assert t0000.equals(t0000) : "equals says t0000 != t0000";
    +                  assert t0059.equals(t0059) : "equals says t0059 != t0059";
    +                  ...
    +                  assert t0000.equals(UTCs.make(0, 0))   : "t0000 != t0000";
    +                  assert t0059.equals(UTCs.make(0, 59))  : "t0059 != t0059";
    +                  ...
    +                  assert ! (t0000.equals(t0059)) : "equals says t0000 = t0059";
    +                  assert ! (t0059.equals(t2359)) : "equals says t0059 = t2359";
    +                  ...
    +                  assert t0000.hashCode() == (UTCs.make(0, 0).hashCode());
    +                  assert t0059.hashCode() == (UTCs.make(0, 59).hashCode());
    +                  ...
    +                  assert t0000.toString().equals(UTCs.make(0, 0).toString());
    +                  assert t0059.toString().equals(UTCs.make(0, 59).toString());
    +                  ...
    +              }
    +      
    +              System.out.println ("UTCs tests passed.");
    +          }
    +      }
    +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/testingObjectsSummary.html b/InterfacesClasses2/testingObjectsSummary.html new file mode 100644 index 0000000..6ae5ceb --- /dev/null +++ b/InterfacesClasses2/testingObjectsSummary.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + Summary + + + + + + + + + + +
    +
    +

    + Summary +

    +
      +
    • + Every class should be tested. +
    • +
    • + When multiple classes implement the same interface, + objects of those classes should be tested for + interchangeability and interoperability. +
    • +
    • + Testing across classes is hard because: +
        +
      • + We may not know all of the classes that implement an interface. +
      • +
      • + More such classes may be added over time as the program evolves. +
      • +
      • + If the tested classes are extended using inheritance, + then their subclasses must be tested as well. +
      • +
      +
    • +
    +
    +
    + + + + + + + + diff --git a/InterfacesClasses2/tostring2.html b/InterfacesClasses2/tostring2.html new file mode 100644 index 0000000..e32af2b --- /dev/null +++ b/InterfacesClasses2/tostring2.html @@ -0,0 +1,99 @@ + + + + + + + + + + + + The toString() Method of Java + + + + + + + + + + +
    +
    +

    + The toString() Method of Java +

    +

    + All Java objects have a toString method that + determines how the object will look when printed. +

    +

    + The specification of the toString method + recommends that all classes define this method. + If a class does not define a toString method, + it will inherit the toString method of its + superclass, which is likely to useless or misleading. +

    +

    + Within the + UTC1 class + of our example, we can define a suitable toString + method like this: +

    +
    +          public String toString () {
    +              return ((Integer) (100 * h + m)).toString();
    +          }
    +
    +

    + Here we see another use for casts. + The type of (100 * h + m) is int, + which is a primitive (uncapitalized) type, + not a reference (capitalized) type. + In Java, the values of a primitive type are not considered + to be objects. + Casting the int expression to Integer + also converts the primitive value into a reference value, + or object, making it possible to call its toString + method. +

    +
    +

    + Some casts of that sort are no longer necessary in the latest + versions of Java, but were necessary in earlier versions. + Writing an explicit cast, as here, reveals the code that would + be executed if the programmer left the cast to be inserted by + the Java compiler. +

    +
    +
    +
    + + + + + + + + diff --git a/Modules/module09.html b/Modules/module09.html index 3ecc09f..94edd08 100644 --- a/Modules/module09.html +++ b/Modules/module09.html @@ -214,17 +214,21 @@

  • - Lesson 9.6: Design Recipe Using Classes - + Lesson 9.6: Design Recipe Using Classes + + (ppt) +(pdf)
  • Problem Set

    - + Problem Set 09 - will be assigned on Monday, 6 November 2017. + +is due on Monday, 13 November 2017, at 6pm local time.

    diff --git a/Modules/module10.html b/Modules/module10.html index 96880f1..738fd28 100644 --- a/Modules/module10.html +++ b/Modules/module10.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,100 +25,122 @@

    CS 5010: Module 10 -

    +

    Module Overview -

    +

    - In this module, we will learn about inheritance, which is a - mechanism that allows us to generalize the implementations - of similar classes. Inheritance allows us to make a new class - that is very similar to an old one, or to make a new class - that generalizes the implementations of several similar classes. -

    + This module introduces abstract data types. + It then covers several Java-specific features + that are related to abstract data types. +

    Course Map -

    - course map + + course map

    Readings -

    +

    No required readings. -

    +

    Resources -

    + +

    + We recommend the following tutorials, especially if you do + not feel comfortable programming in Java. +

    +

    + We use Java's standard libraries as a source of examples: +

    + + + Application Programming Interface for Java 8 + + + + + +Examples for this module + +

    Lessons -

    + + + Lesson 10.4: Testing Simple Objects + + +

    Problem Set -

    +

    - - Problem Set 10 - - was assigned on Monday, 27 March. -

    -
    + + Problem Set 10 +is due on Monday, 27 November 2017, at 6pm local time. +

    + +
    + + diff --git a/Modules/module11.html b/Modules/module11.html index 36ec6fd..f899415 100644 --- a/Modules/module11.html +++ b/Modules/module11.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,62 +25,131 @@

    CS 5010: Module 11 -

    +

    Module Overview -

    +

    - In this module, we will consider the advantages of disadvantages - of objects with mutable state, with an eye towards developing - general rules of thumb for when to use stateful objects and - when to avoid them. -

    -

    - Along the way, we will consider several design patterns - that depend on stateful objects. -

    + In this module, we will learn about inheritance, which is a + mechanism that allows us to generalize the implementations + of similar classes. Inheritance allows us to make a new class + that is very similar to an old one, or to make a new class + that generalizes the implementations of several similar classes. +

    Course Map -

    - course map + + course map

    Readings -

    +

    No required readings. -

    +

    Resources -

    + + +
  • + + Trail: Learning the Java Language + +
    + (You can use this as a reference manual for the Java language. + The real + + reference manuals for Java + + are far more detailed, and tell you more than you need to know + for this course.) +
  • +
  • + + Application Programming Interface for Java 8 + + +
  • +
  • + Chris Okasaki. + + Red-black + Trees in a Functional Setting, + + + Journal of Functional Programming, + + 9(4) 471–477, July 1999. +
  • +

    Lessons -

    -

    - No online lessons. - The material of this module will be covered by lectures. -

    + +

    Problem Set -

    +

    - Problem Set 11 - - was assigned on Monday, 3 April. -

    -
    + Problem Set 11 + is due on Monday, 4 December 2017 at 6pm local time. +

    +

    + Problem Set 11 will be the last problem set. +

    +
    + + diff --git a/Modules/module12.html b/Modules/module12.html index f59bab2..83b5f57 100644 --- a/Modules/module12.html +++ b/Modules/module12.html @@ -1,178 +1,136 @@ - - - - - - - - - - - - CS 5010: Module 12 - - - - - - - - - - -
    -

    - CS 5010: Module 12 -

    -
    -

    - Module Overview -

    -

    - In this module, we will examine how efficiency is related - to programming style, programming languages, and how - programming languages are implemented. -

    -

    - These matters are largely unrelated to algorithmic complexity, - so they are seldom discussed in courses on algorithms and - data structures. - Programmers often form opinions based on what they have heard - from other programmers or have read on the World-Wide Web, - which are not particularly reliable sources. - As it turns out, much of the conventional wisdom concerning - programming style and efficiency is misleading or, - in some cases, quite wrong. -

    -

    - Readings -

    -

    - No required readings. -

    -

    - Resources -

    - -

    - Examples will be added soon. -

    -

    - Lessons -

    -

    - The material of this module will be covered by lecture, - demonstrations, and a problem set. - Online lessons will be added below as time permits. -

    - -

    - Problem Set -

    -

    - - Problem Set 12 - - was assigned on Monday, 10 April. -

    -
    -
    - - - -

    -For debugging: - -Click here to validate. - -

    - - - + + + +CS 5010 Module 12 + + + + + + + + +
    + +

    CS 5010 Module 12

    + +

    Module Overview

    + +

    Now that you have completed work on your problem sets, this week's +module is a special bonus module containing material at each +instructor's discretion.

    + +

    The materials for this module include some supplementary lessons +from Professor Clinger's Spring 2017 offering of CS 5010. These +lessons contain important knowledge that you should know as you move +forward in your careers.

    + +

    In Lesson 12.1, we summarize the main points of this course and +give you a pep talk as you go on to the rest of your Master's +program.

    + +

    Course Map

    + +course map, week 12 + +

    Supplementary Lessons

    + +

    The following lessons are from Professor Clinger's Spring 2017 +offering of CS 5010.

    + + + +

    Lessons and Guided Practices

    + + + + +

    Problem Set

    + +

    Go out in the world and do good work!

    + +
    + + +
    + + diff --git a/Pdfs/Lesson 8.1 General Recursion.pdf b/Pdfs/Lesson 8.1 General Recursion.pdf new file mode 100644 index 0000000..e855d31 Binary files /dev/null and b/Pdfs/Lesson 8.1 General Recursion.pdf differ diff --git a/Pdfs/Lesson 8.2 Binary Search.pdf b/Pdfs/Lesson 8.2 Binary Search.pdf new file mode 100644 index 0000000..c8ed282 Binary files /dev/null and b/Pdfs/Lesson 8.2 Binary Search.pdf differ diff --git a/Pdfs/Lesson 9.6 The Design Recipe Using Classes.pdf b/Pdfs/Lesson 9.6 The Design Recipe Using Classes.pdf new file mode 100644 index 0000000..ed330df Binary files /dev/null and b/Pdfs/Lesson 9.6 The Design Recipe Using Classes.pdf differ diff --git a/ProblemSets/UTC.java b/ProblemSets/UTC.java deleted file mode 100644 index a614ee9..0000000 --- a/ProblemSets/UTC.java +++ /dev/null @@ -1,18 +0,0 @@ -// A UTC is an object of any class that implements UTC. -// -// Interpretation: A UTC represents a Universal Coordinated Time. - -interface UTC { - - // Returns the hour, between 0 and 23 inclusive. - - int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - boolean isEqual (UTC t2); -} diff --git a/ProblemSets/ps08.html b/ProblemSets/ps08.html index b681e1f..650cd8d 100644 --- a/ProblemSets/ps08.html +++ b/ProblemSets/ps08.html @@ -99,7 +99,7 @@

    Tell git to add your work session report to the files you will commit, and then commit and push (sync) that report in addition to - committing and pushing your entire set06 directory. + committing and pushing your entire set06set08 directory. Do this at the end of every work session.

    @@ -367,8 +367,8 @@

    ;;; "A" ; outranked by 0, outranks 3 ;;; "F" ; outranked by 1 ;;; "E" ; outranked by 3 - ;;; "B" ; outranked by 4, outranks 1, 50% - ;;; "D") ; outranked by 4, outranks 1, 50% + ;;; "B" ; outranked by 4, outranks 12, 50% + ;;; "D") ; outranked by 4, outranks 12, 50%

    Instead of copying most of your q1.rkt file diff --git a/ProblemSets/ps09.html b/ProblemSets/ps09.html index 6e0c0a3..3163e34 100644 --- a/ProblemSets/ps09.html +++ b/ProblemSets/ps09.html @@ -1,285 +1,323 @@ - - - - - - - - - - - - CS 5010: Problem Set 09 - - - - - - - - - - -

    -

    - CS 5010: Problem Set 09 -

    -
    -

    - Out: Monday, 20 March 2017 -
    - Due: Monday, 27 March 2017 at 6pm -

    -
    -
    -

    - This is a - - pair programming - - assignment. You are required to - complete this problem set in collaboration with your assigned - partner, but neither of you are allowed to - discuss this problem set with any other person. You are also - not allowed to search for or to view any solutions to similar - problems that may be available on the World-Wide Web or in - other resources that might otherwise have been available to - you. -

    -

    - We have created a repository for you and your partner to use - in this problem set and for the next two problem sets as well. - The name of that repository is of the form - pdp-ID1-ID2, - where ID1 is either your CCIS ID - or your partner's CCIS ID, and ID2 - is the other CCIS ID for your team. -

    -

    - In those repositories, we have created files named - ID1-log.txt and - ID2-log.txt for you to use when - filing work session reports, as in previous problem sets. - You and your partner are required to push your files at - the end of every work session. - (You may push your files several times during - a work session, but we do not require you to do so.) -

    -

    - At the end of every work session, you are required to update - your log file to record the time you spent in that work session. - (Please do not include the time you spent in any previous work - sessions, as those times will already have been recorded in - previous versions of your log file.) - If both of you work together during a work session, both of - you must update your log files, recording only the time you - spent working. Do not include your partner's time in - your log file, but be sure to push the updated versions of - both log files. -

    -
    -

    - The main purpose of this problem set is to give you practice - applying what you have learned in previous assignments to - object-oriented programming in Java. -

    -

    - You must use Java 8 for this assignment. - All of your code must reside within the default package. - You may use/import anything in the - java.lang and java.util - packages, but you are not allowed to use any other packages. -

    -
    -
    -

    - Problem Specification -

    -

    - You will translate your polynomial-time solution to the flight - scheduling problem from Racket to Java. - Your translation will use the data types specified in this - problem set, which will allow us to write black-box tests - we can use to test all of the solutions submitted by students - taking the course. -

    -

    - We have divided that problem into two parts. - In the first part, you will implement three abstract data types. - In the second part, you will use those ADTs in your solution to - the scheduling problem. -

    -
      -
    1. - We are giving you three Java files, which define three - abstract data types: - UTC, - Flight, and - RacketList<E>. - You must copy those three files into your team's - set09 directory without changing them in any way. -

      - In a file named UTCs.java, define a public class - named UTCs that defines the following - public static factory method: -

      -
      -        // GIVEN: the hour in [0,23] and the minute in [0,59]
      -        // RETURNS: a UTC with that hour and minute
      -        
      -        public static UTC make (int h, int m) {
      -            ...
      -        }
      -      
      -

      - In a file named Flights.java, define a public class - named Flights that defines the following - public static factory method: -

      -
      -        // GIVEN: the name of a flight, the name of the airport from
      -        //     which the flight departs, the name of the airport at
      -        //     which the flight arrives, the time of departure in UTC,
      -        //     and the time of arrival in UTC
      -        // RETURNS: a flight value that encapsulates the given information
      -        
      -        public static Flight make (String s, String ap1, String ap2,
      -                                   UTC t1, UTC t2) {
      -            ...
      -        }
      -      
      -

      - In a file named RacketLists.java, define a public class - named RacketLists that defines the following - public static factory method: -

      -
      -        // GIVEN: no arguments
      -        // RETURNS: an empty RacketList<E>
      -        
      -        public static <E> RacketList<E> empty () {
      -            ...
      -        }
      -      
      -

      - You may add more static methods to those three classes - if you wish. -

      -

      - Complete your implementation of the three ADTs specified above - by defining more classes. You will probably want to put at - least some of those classes in separate files, but all files - must be added to your set09 directory and pushed - to your team's repository. -

      -
    2. -
    3. - In the second part of this problem set, you will translate your - polynomial-time solution to the scheduling problem from Racket - to Java. -

      - We are giving you a - FlightExamples.java - file that defines the lists of flights used in the examples below. - You will need to define more lists of flights for use in your own - testing. In particular, you will need to write benchmarks that - test the performance of the three methods specified below. -

      -

      - In a file named Schedules.java, define a public class - named Schedules that defines the following - public static methods: -

      -
      -        // GIVEN: the names of two airports, ap1 and ap2 (respectively),
      -        //     and a RacketList<Flight> that describes all of the flights a
      -        //     traveller is willing to consider taking
      -        // RETURNS: true if and only if it is possible to fly from the
      -        //     first airport (ap1) to the second airport (ap2) using
      -        //     only the given flights
      -        // EXAMPLES:
      -        //     canGetThere ("06N", "JFK", FlightExamples.panAmFlights)  =>  false
      -        //     canGetThere ("JFK", "JFK", FlightExamples.panAmFlights)  =>  true
      -        //     canGetThere ("06N", "LAX", FlightExamples.deltaFlights)  =>  false
      -        //     canGetThere ("LAX", "06N", FlightExamples.deltaFlights)  =>  false
      -        //     canGetThere ("LGA", "PDX", FlightExamples.deltaFlights)  =>  true
      -        
      -        public static boolean canGetThere (String ap1,
      -                                           String ap2,
      -                                           RacketList<Flight> flights) {
      -            ...
      -        }
      -                
      -        // GIVEN: the names of two airports, ap1 and ap2 (respectively),
      -        //     and a RacketList<Flight> that describes all of the flights a
      -        //     traveller is willing to consider taking
      -        // WHERE: it is possible to fly from the first airport (ap1) to
      -        //     the second airport (ap2) using only the given flights
      -        // RETURNS: a list of flights that tells how to fly from the
      -        //     first airport (ap1) to the second airport (ap2) in the
      -        //     least possible time, using only the given flights
      -        // NOTE: to simplify the problem, your program should incorporate
      -        //     the totally unrealistic simplification that no layover
      -        //     time is necessary, so it is possible to arrive at 1500
      -        //     and leave immediately on a different flight that departs
      -        //     at 1500
      -        // EXAMPLES:
      -        //     fastestItinerary ("JFK", "JFK", FlightExamples.panAmFlights)
      -        //         =>  RacketLists.empty()
      -        //
      -        //     fastestItinerary ("LGA", "PDX", FlightExamples.deltaFlights)
      -        // =>  RacketLists.empty().cons
      -        //         (Flights.make ("Delta 2163",
      -        //                        "MSP", "PDX",
      -        //                        UTCs.make (15, 0), UTCs.make (19, 2))).cons
      -        //             (Flights.make ("Delta 0121",
      -        //                            "LGA", "MSP",
      -        //                            UTCs.make (11, 0),
      -        //                            UTCs.make (14, 9)))
      -        //
      -        // (Note: The Java syntax for a method call makes those calls
      -        // to cons look backwards from what you're used to in Racket.)
      -        
      -        public static
      -            RacketList<Flight> fastestItinerary (String ap1,
      -                                                 String ap2,
      -                                                 RacketList<Flight> flights) {
      -            ...
      -        }
      -        
      -        // GIVEN: the names of two airports, ap1 and ap2 (respectively),
      -        //     and a RacketList<Flight> that describes all of the flights a
      -        //     traveller is willing to consider taking
      -        // WHERE: it is possible to fly from the first airport (ap1) to
      -        //     the second airport (ap2) using only the given flights
      -        // RETURNS: the number of minutes it takes to fly from the first
      -        //     airport (ap1) to the second airport (ap2), including any
      -        //     layovers, by the fastest possible route that uses only
      -        //     the given flights
      -        // EXAMPLES:
      -        //     travelTime ("JFK", "JFK", FlightExamples.panAmFlights)  =>  0
      -        //     travelTime ("LGA", "PDX", FlightExamples.deltaFlights)  =>  482
      -        
      -        public static int travelTime (String ap1,
      -                                      String ap2,
      -                                      RacketList<Flight> flights) {
      -            ...
      -        }
      -      
      -
    4. -
    -
    - - - -

    -For debugging: - -Click here to validate. - -

    - - - + + + + + + + + + + + + CS 5010: Problem Set 09 + + + + + + + + + + +
    +

    + CS 5010: Problem Set 09 +

    +
    +

    + Out: Monday, 6 November 2017 +
    + Due: Monday, 13 November 2017 at 6pm local time +

    +
    +
    +

    + This is an individual assignment. You are not allowed to + discuss this problem set with any other person. You are also + not allowed to search for or to view any solutions to similar + problems that may be available on the World-Wide Web or in + other resources that might otherwise have been available to + you. +

    +

    + The main purpose of this problem set is to give you practice + using interfaces and defining classes in Java. +

    +

    + We will test your program using Java 8, + which is the version of Java installed on CCIS Linux machines. + You will therefore want to use Java 8 when developing and + testing your program. +

    +

    + For these problems, we are giving you the following files: +

    +
      +
    • + Outcome.java +
    • +
    • + Tie1.java + (incomplete!) +
    • +
    • + Defeat1.java + (incomplete!) +
    • +
    • + Competitor.java +
    • +
    • + Competitor1.java + (incomplete!) +
    • +
    +

    + Three of those files are marked as incomplete. + Your job is to complete those three files. +

    +

    + As you complete those three files, you should leave them + in the default package. + In other words, your Java files should not contain any + package declarations. +

    +

    + You must not change any of the other files in any way. +

    + + +

    + You should start by downloading the files we are giving you, + unpacking them into a set09 directory, + and pushing that directory to your GitHub repository. +

    +

    + We are giving you a choice of two formats in which to download + the files we are giving you. Both of these links will unpack + to the same set09 directory containing exactly + the same Java files: +

    + +

    + Remember that you must follow the design recipe, which is a + process, not a list of deliverables. +

    +

    + Be sure to fill out a + work session report + at the end of each work session. + Be sure to report only the hours + spent in that work session; + do not report the cumulative time. + Tell git to add your work session report + to the files you will commit, + and then commit and push (sync) that report in addition to + committing and pushing your entire set09 directory. + Do this at the end of every work session. +

    +
    +

    + This problem set asks you to define three Java classes + that implement the Java interfaces we are giving you. + The three classes you define will perform essentially + the same computations as the program you wrote for + Problem Set 08. +

    +

    + There are some differences, however. +

    +

    + In Problem Set 08, you defined functions named + tie and defeated + whose results represent an Outcome. + For Problem Set 09, you will define classes named + Tie1 and Defeat1 that + implement the interface given in Outcome.java: +

    +
    +      // An Outcome is an object of any class that implements Outcome
    +      //
    +      // Interpretation: the two competitors have engaged in a contest
    +      //   If this.isTie() is true, the contest ended in a tie.
    +      //   Otherwise the contest did not end in a tie, and
    +      //       this.winner() defeated this.loser()
    +      
    +      interface Outcome {
    +      
    +          // RETURNS: true iff this outcome represents a tie
    +      
    +          boolean isTie ();
    +      
    +          // RETURNS: one of the competitors
    +      
    +          Competitor first ();
    +      
    +          // RETURNS: the other competitor
    +      
    +          Competitor second ();
    +      
    +          // GIVEN: no arguments
    +          // WHERE: this.isTie() is false
    +          // RETURNS: the winner of this outcome
    +      
    +          Competitor winner ();
    +      
    +          // GIVEN: no arguments
    +          // WHERE: this.isTie() is false
    +          // RETURNS: the loser of this outcome
    +      
    +          Competitor loser ();
    +      }
    +
    +

    + In Problem Set 08, a Competitor + was just a String. + For Problem Set 09, you will define a class named + Competitor1 + that implements the interface given in + Competitor.java: +

    +
    +      // A Competitor is an object of any class that implements Competitor
    +      //
    +      // Interpretation: the competitor represents an individual or team
    +      //     that may have engaged in one or more contests
    +      
    +      // Note:  In Java, you cannot assume a List is mutable, because all
    +      // of the List operations that change the state of a List are optional.
    +      // Mutation of a Java list is allowed only if a precondition or other
    +      // invariant says the list is mutable and you are allowed to change it.
    +      
    +      import java.util.List;
    +      
    +      interface Competitor {
    +      
    +          // returns the name of this competitor
    +      
    +          String name ();
    +      
    +          // GIVEN: another competitor and a list of outcomes
    +          // RETURNS: true iff one or more of the outcomes indicates this
    +          //     competitor has defeated or tied the given competitor
    +      
    +          boolean hasDefeated (Competitor c2, List<Outcome> outcomes);
    +      
    +          // GIVEN: a list of outcomes
    +          // RETURNS: a list of the names of all competitors mentioned by
    +          //     the outcomes that are outranked by this competitor,
    +          //     without duplicates, in alphabetical order
    +      
    +          List<String> outranks (List<Outcome> outcomes);
    +      
    +          // GIVEN: a list of outcomes
    +          // RETURNS: a list of the names of all competitors mentioned by
    +          //     the outcomes that outrank this competitor,
    +          //     without duplicates, in alphabetical order
    +      
    +          List<String> outrankedBy (List<Outcome> outcomes);
    +      
    +          // GIVEN: a list of outcomes
    +          // RETURNS: a list of the names of all competitors mentioned by
    +          //     one or more of the outcomes, without repetitions, with
    +          //     the name of competitor A coming before the name of
    +          //     competitor B in the list if and only if the power ranking
    +          //     of A is higher than the power ranking of B.
    +      
    +          List<String> powerRanking (List<Outcome> outcomes);
    +      }
    +
    +
    + +

    To help you plan your work, we have divided this problem into two +questions. However, you should submit a single +set09 directory containing your class definitions and other +deliverables for both questions 1 and 2.

    + +
      +
    1. + (Outcome) +
      +

      + For this first part of Problem Set 09, you will complete + the Tie1 and Defeat1 classes + we started to define for you in the + Tie1.java and + Defeat1.java files. +

      +

      + You will not be able to test your + Tie1 and Defeat1 classes + until you define a class that implements the + Competitor interface. + For testing, however, you can define a + Competitor1 class that supports + the name method but throws an + UnsupportedOperationException + whenever the other methods of the + Competitor interface are called. + The Competitor1.java file we are giving you + already throws that exception whenever the + hasDefeated, + outranks, + outrankedBy, or + powerRanking methods are called. +

      +
    2. +
    3. + (Competitor) +
      +

      + For this second part of Problem Set 09, + you are to replace the stubs we have given you for the + hasDefeated, + outranks, + outrankedBy, and + powerRanking methods + by definitions that satisfy the contracts and purpose statements + given in the Competitor interface. +

      +

      + The concepts used in the descriptions of + those methods are the same as in Problem Set 08. + If your solution for Problem Set 08 was correct, + you can just translate your solution into Java. + If your solution for Problem Set 08 was incorrect, + you will probably want to debug it in Racket's + ISL+Lambda language before you try to translate it + into Java. +

      +
    4. +
    +
    +
    + + + + + + + diff --git a/ProblemSets/ps10.html b/ProblemSets/ps10.html index 021bb40..f4ddaf6 100644 --- a/ProblemSets/ps10.html +++ b/ProblemSets/ps10.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,554 +25,338 @@

    CS 5010: Problem Set 10 -

    +

    - Out: Monday, 27 March 2017 + Out: Monday, 13 November 2017
    - Due: Monday, 3 April 2017 at 6pm -
    - Corrected: Tuesday, 28 March 2017 - (minor corrections and clarifications) -
    - Corrected: Saturday, 1 April 2017 - (purpose statement for ConstantExp) -

    -
    + Due: Monday, 27 November 2017 at 6pm local time +

    +

    - This is a - - pair programming - - assignment. You are required to - complete this problem set in collaboration with your assigned - partner, but neither of you are allowed to + This is an individual assignment. You are not allowed to discuss this problem set with any other person. You are also not allowed to search for or to view any solutions to similar problems that may be available on the World-Wide Web or in other resources that might otherwise have been available to you. -

    +

    +

    + The main purpose of this problem set is to give you practice + implementing abstract data types, both mutable and immutable. + The problem set will also give you some practice implementing + equals(Object), + hashCode(), + toString(), and + iterator() + methods. +

    +

    + We will test your program using Java 8, + which is the version of Java installed on CCIS Linux machines. + You will therefore want to use Java 8 when developing and + testing your program. +

    +

    + For these problems, we are giving you the following files: +

    +
      +
    • + Player.java +
    • +
    • + Roster.java +
    • +
    +

    + You must not change those files in any way. +

    +

    + Parts 1 and 2 of this problem set ask you to create two + more files named + Players.java and + Rosters.java. + Both of those files must be in the default package. + In other words, your Java files should not contain any + package declarations. +

    +

    + You are free to create additional files. + When we test your submission, we will compile all of the + Java files in your set10 directory using the + following command: +

    +
    +      javac *.java
    +

    - We have created a repository for you and your partner to use. -

    + You should start by downloading the two files we are giving you, + unpacking them into a set10 directory, + and pushing that directory to your GitHub repository. +

    - In those repositories, we have created files named - ID1-log.txt and - ID2-log.txt for you to use when - filing work session reports, as in previous problem sets. - You and your partner are required to push your files at - the end of every work session. - (You may push your files several times during - a work session, but we do not require you to do so.) -

    + We are giving you a choice of two formats in which to download + the files we are giving you. Both of these links will unpack + to the same set10 directory containing exactly + the same Java files: +

    +

    - At the end of every work session, you are required to update - your log file to record the time you spent in that work session. - (Please do not include the time you spent in any previous work - sessions, as those times will already have been recorded in - previous versions of your log file.) - If both of you work together during a work session, both of - you must update your log files, recording only the time you - spent working. Do not include your partner's time in - your log file, but be sure to push the updated versions of - both log files. -

    + Remember that you must follow the design recipe, which is a + process, not a list of deliverables. +

    +

    + Be sure to fill out a + work session report + at the end of each work session. + Be sure to report only the hours + spent in that work session; + do not report the cumulative time. + Tell git to add your work session report + to the files you will commit, + and then commit and push (sync) that report in addition to + committing and pushing your entire set10 directory. + Do this at the end of every work session. +


    - The main purpose of this problem set is to give you practice - implementing abstract data types and using inheritance in - Java. - You will also learn something about programming languages - and how they are implemented. -

    + This problem set asks you to implement two abstract data types, + Player and Roster. + These ADTs would be useful to the coaches of a team sport + as they consider different rosters they might use for an + upcoming game. + In the NFL, for example, a team's roster can contain up to + 53 players, but some of those players may be unavailable + because of suspension or injury. + On game day, the head coach must designate a smaller roster + with no more than 46 players, and coaches routinely consider + several of those smaller rosters before deciding which roster to + use in the game. +

    - You must use Java 8 for this assignment. - All of your code must reside within the default package. - You may use/import anything in the - java.lang and java.util - packages, but you are not allowed to use any other packages. -

    + To make it easier to consider several similar rosters, the + Roster ADT is immutable. + The Player ADT is mutable, however, because an + injury, trade, or some other change to a player's status should + be propagated immediately to all rosters that use the player. +

    +
    +      // A Player is an object of any class that implements the Player interface.
    +      //
    +      // A Player object represents a member of a team.
    +      // Player objects are mutable because their status can change without
    +      // changing the identity of the Player.
    +      // 
    +      // If p1 and p2 are players, then p1.equals(p2) if and only if
    +      // p1 and p2 are the same object (i.e. (p1 == p2), p1 and p2
    +      // have the same name and status, and changing the status of p1
    +      // necessarily changes the status of p2 in the same way).
    +      //
    +      // If p is a player, then p.hashCode() always returns the same
    +      // value, even after the player's status is changed by calling
    +      // one of the last three methods listed below.
    +      //
    +      // If p1 and p2 are players with distinct names, then
    +      // p1.toString() is not the same string as p2.toString().
    +      //
    +      // Players.make(String name) is a static factory method that returns
    +      // a player with the given name who is (initially) available.
    +      
    +      interface Player {
    +      
    +          // Returns the name of this player.
    +          // Example:
    +          //     Players.make("Gordon Wayhard").name()  =>  "Gordon Wayhard"
    +      
    +          String name ();
    +      
    +          // Returns true iff this player is
    +          //     under contract, and
    +          //     not injured, and
    +          //     not suspended
    +          // Example:
    +          //     Player gw = Players.make ("Gordon Wayhard");
    +          //     System.out.println (gw.available());  // prints true
    +          //     gw.changeInjuryStatus (true);
    +          //     System.out.println (gw.available());  // prints false
    +      
    +          boolean available ();
    +      
    +          // Returns true iff this player is under contract (employed).
    +          // Example:
    +          //     Player ih = Players.make ("Isaac Homas");
    +          //     System.out.println (ih.underContract());  // prints true
    +          //     ih.changeContractStatus (false);
    +          //     System.out.println (ih.underContract());  // prints false
    +          //     ih.changeContractStatus (true);
    +          //     System.out.println (ih.underContract());  // prints true
    +      
    +          boolean underContract ();
    +      
    +          // Returns true iff this player is injured.
    +      
    +          boolean isInjured ();
    +      
    +          // Returns true iff this player is suspended.
    +      
    +          boolean isSuspended ();
    +      
    +          // Changes the underContract() status of this player
    +          // to the specified boolean.
    +      
    +          void changeContractStatus (boolean newStatus);
    +      
    +          // Changes the isInjured() status of this player
    +          // to the specified boolean.
    +      
    +          void changeInjuryStatus (boolean newStatus);
    +      
    +          // Changes the isSuspended() status of this player
    +          // to the specified boolean.
    +      
    +          void changeSuspendedStatus (boolean newStatus);
    +      }
    +
    +
    +      // A Roster is an object of any class that implements the Roster interface.
    +      //
    +      // A Roster object represents a set of players.
    +      //
    +      // Roster objects are immutable, but all players on a roster
    +      // have mutable status, which can affect the values returned by
    +      // the readyCount() and readyRoster() methods.
    +      //
    +      // If r1 and r2 are rosters, then r1.equals(r2) if and only if
    +      // every player on roster r1 is also on roster r2, and
    +      // every player on roster r2 is also on roster r1.
    +      //
    +      // If r is a roster, then r.hashCode() always returns the same
    +      // value, even if r has some players whose status changes.
    +      //
    +      // If r1 and r2 are rosters of different sizes, then
    +      // r1.toString() is not the same string as r2.toString().
    +      //
    +      // Rosters.empty() is a static factory method that returns an
    +      // empty roster.
    +      
    +      import java.util.Iterator;
    +      
    +      interface Roster extends Iterable<Player> {
    +      
    +          // Returns a roster consisting of the given player together
    +          // with all players on this roster.
    +          // Example:
    +          //     r.with(p).with(p)  =>  r.with(p)
    +      
    +          Roster with (Player p);
    +      
    +          // Returns a roster consisting of all players on this roster
    +          // except for the given player.
    +          // Examples:
    +          //     Rosters.empty().without(p)  =>  Rosters.empty()
    +          //     r.without(p).without(p)     =>  r.without(p)
    +      
    +          Roster without (Player p);
    +      
    +          // Returns true iff the given player is on this roster.
    +          // Examples:
    +          //
    +          //     Rosters.empty().has(p)  =>  false
    +          //
    +          // If r is any roster, then
    +          //
    +          //     r.with(p).has(p)     =>  true
    +          //     r.without(p).has(p)  =>  false
    +      
    +          boolean has (Player p);
    +      
    +          // Returns the number of players on this roster.
    +          // Examples:
    +          //
    +          //     Rosters.empty().size()  =>  0
    +          //
    +          // If r is a roster with r.size() == n, and r.has(p) is false, then
    +          //
    +          //     r.without(p).size()          =>  n
    +          //     r.with(p).size()             =>  n+1
    +          //     r.with(p).with(p).size()     =>  n+1
    +          //     r.with(p).without(p).size()  =>  n
    +      
    +          int size ();
    +      
    +          // Returns the number of players on this roster whose current
    +          // status indicates they are available.
    +      
    +          int readyCount ();
    +      
    +          // Returns a roster consisting of all players on this roster
    +          // whose current status indicates they are available.
    +      
    +          Roster readyRoster ();
    +      
    +          // Returns an iterator that generates each player on this
    +          // roster exactly once, in alphabetical order by name.
    +      
    +          Iterator<Player> iterator ();
    +      }
    +
    + +You may not change these interfaces in any way, but you may define new + interfaces that extend them. +
    -
    -

    - Problem Specification -

    -

    - You will write an interpreter for a simple functional - programming language with this concrete syntax: -

    -
    -    <pgm>     ::=  <defn> ;
    -              ::=  <defn> ; <pgm>
    -    <defn>    ::=  <id> = <const>
    -              ::=  <id> (<formals>) <expr>
    -    <const>   ::=  true 
    -              ::=  false
    -              ::=  <int>
    -    <lambda>  ::=  (λ ( <formals> ) <expr>)
    -    <expr>    ::=  <const>
    -              ::=  <id>
    -              ::=  <lambda>
    -              ::=  <arith>
    -              ::=  <call>
    -              ::=  <if>
    -              ::=  ( <expr> )
    -    <arith>   ::=  <expr> <op> <expr>
    -    <call>    ::=  <expr> (<exprs>)
    -    <if>      ::=  if <expr> then <expr> else <expr> fi
    -    
    -    <op>      ::=  < | = | > | + | - | *
    -    
    -    <formals>  ::=  <id>
    -               ::=  <id> , <formals>
    -    <exprs>    ::=  <expr>
    -               ::=  <expr> , <exprs>
    -    
    -    <int> and <id> are described by regular expressions:
    -    
    -        digit digit*
    -    
    -        letter (letter | digit)*
    -  
    -

    - That concrete syntax may be easy - for humans to read, but it is not a convenient representation - for compilers or interpreters. - Compilers and interpreters generally use a more convenient - internal representation known as - abstract syntax trees. - (Abstract syntax trees are closely related to the list representation - of programs used in Lisp/Scheme/Racket/Clojure, and to the XML - notation used to represent more general kinds of data.) -

    -

    - For the programming language above, we need abstract syntax trees - for programs, definitions, and expressions. - There are six different kinds of expressions, - so we need six different kinds of abstract syntax trees for - expressions. - That gives us the following conceptual hierarchy: -

    -
    -    Ast
    -        Pgm
    -        Def
    -        Exp
    -            ConstantExp
    -            IdentifierExp
    -            LambdaExp
    -            ArithmeticExp
    -            CallExp
    -            IfExp
    -  
    -

    - We will represent the abstract syntax tree for a program - as a List<Def>. - All of the other categories within that hierarchy will be - represented by the Java interfaces shown below. - To save you from having to copy and paste those interfaces, - we are giving you the Java source files as a - gzip'ed tar file, - set10.tgz. - When you unpack that file, it will expand into a - set10 directory that already contains the - following Java source files. -

    -

    - Abstract Syntax Trees -

    -

    - The Ast.java file: -

    -
    -    // An Ast is an object of any class that implements the Ast interface.
    -    //
    -    // Interpretation: An Ast represents the abstract syntax tree
    -    // for some part of a source program.
    -    //
    -    // This abstract data type simplies the parser,
    -    // but should not be used by the type checker or interpreter.
    -    
    -    import java.util.List;
    -    
    -    interface Ast {
    -    
    -        // Returns true iff this Ast is for a program, definition,
    -        // or expression, respectively
    -    
    -        boolean isPgm();
    -        boolean isDef();
    -        boolean isExp();
    -    
    -        // Precondition: this Ast is for a program.
    -        // Returns a representation of that program.
    -    
    -        List<Def> asPgm();
    -    
    -        // Precondition: this Ast is for a definition.
    -        // Returns a representation of that definition.
    -    
    -        Def asDef();
    -    
    -        // Precondition: this Ast is for an expression.
    -        // Returns a representation of that expression.
    -    
    -        Exp asExp();
    -    }
    -  
    -

    - Definitions -

    -

    - The Def.java file: -

    -
    -    // A Def is an object of any class that implements the Def interface.
    -    //
    -    // Interpretation: A Def represents one definition of the source program.
    -    
    -    interface Def extends Ast {
    -    
    -        // Returns the left hand side of this definition,
    -        // which will be an identifier represented as a String.
    -    
    -        String lhs();
    -    
    -        // Returns the right hand side of this definition,
    -        // which will be a ConstantExp or a LambdaExp.
    -    
    -        Exp rhs();
    -    }
    -  
    -

    - Expressions -

    -

    - The Exp.java file: -

    -
    -    // An Exp is an object of any class that implements the Exp interface.
    -    //
    -    // Interpretation: An Exp represents an expression of a source program.
    -    
    -    import java.util.Map;
    -    
    -    interface Exp extends Ast {
    -    
    -        // Returns true iff this Exp is a constant, identifier,
    -        // lambda, arithmetic, call, or if expression (respectively).
    -    
    -        boolean isConstant();
    -        boolean isIdentifier();
    -        boolean isLambda();
    -        boolean isArithmetic();
    -        boolean isCall();
    -        boolean isIf();
    -    
    -        // Precondition: the corresponding predicate above is true.
    -        // Returns this.
    -        // (These methods amount should eliminate most casts.)
    -    
    -        ConstantExp   asConstant();
    -        IdentifierExp asIdentifier();
    -        LambdaExp     asLambda();
    -        ArithmeticExp asArithmetic();
    -        CallExp       asCall();
    -        IfExp         asIf();
    -    
    -        // Returns the value of this expression when its free variables
    -        //     have the values associated with them in the given Map.
    -        // May run forever if this expression has no value.
    -        // May throw a RuntimeException if some free variable of this
    -        //     expression is not a key of the given Map or if a type
    -        //     error is encountered during computation of the value.
    -    
    -        ExpVal value (Map<String,ExpVal> env);
    -    }
    -  
    -

    - The other *Exp.java files: -

    -
    -    // A ConstantExp is an object of any class that implements ConstantExp.
    -    //
    -    // Interpretation: A ConstantExp represents an identifier (or variable) integer or boolean constant.
    -    
    -    interface ConstantExp extends Exp {
    -    
    -        // Returns the value of this constant expression.
    -    
    -        ExpVal value();
    -    }
    -  
    -
    -    // An IdentifierExp is an object of any class that implements IdentifierExp.
    -    //
    -    // Interpretation: A IdentifierExp represents an identifier (or variable).
    -    
    -    interface IdentifierExp extends Exp {
    -    
    -        // Returns the name of this identifier.
    -    
    -        String name();
    -    }
    -  
    -
    -    // A LambdaExp is an object of any class that implements LambdaExp.
    -    //
    -    // Interpretation: A LambdaExp represents a lambda expression.
    -    
    -    import java.util.List;
    -    
    -    interface LambdaExp extends Exp {
    -    
    -        // Returns the formal parameters of this lambda expression.
    -    
    -        List<String> formals();
    -    
    -        // Returns the body of this lambda expression.
    -    
    -        Exp body();
    -    }
    -  
    -
    -    // An ArithmeticExp is an object of any class that implements ArithmeticExp.
    -    //
    -    // Interpretation: An ArithmeticExp represents an expression of the form
    -    //
    -    //       
    -    
    -    interface ArithmeticExp extends Exp {
    -    
    -        // Returns the appropriate subexpression.
    -    
    -        Exp leftOperand();
    -        Exp rightOperand();
    -    
    -        // Returns the binary operation as one of the strings
    -        //     "LT"
    -        //     "EQ"
    -        //     "GT"
    -        //     "PLUS"
    -        //     "MINUS"
    -        //     "TIMES"
    -    
    -        String operation();
    -    }
    -  
    -
    -    // A CallExp is an object of any class that implements CallExp.
    -    //
    -    // Interpretation: A CallExp represents a function call.
    -    
    -    import java.util.List;
    -    
    -    interface CallExp extends Exp {
    -    
    -        // Returns the expression for the function part of the call.
    -    
    -        Exp operator();
    -    
    -        // Returns the list of argument expressions.
    -    
    -        List<Exp> arguments();
    -    }
    -  
    -
    -    // An IfExp is an object of any class that implements IfExp.
    -    //
    -    // Interpretation: An IfExp represents an if expression.
    -    
    -    interface IfExp extends Exp {
    -    
    -        // Returns the appropriate part of this if expression.
    -    
    -        Exp testPart();
    -        Exp thenPart();
    -        Exp elsePart();
    -    }
    -  
    -

    - Expression Values -

    -

    - The value of an expression in this language will always be - a boolean, integer, or function. -

    -
    -    // An ExpVal is an object of any class that implements the ExpVal interface.
    -    //
    -    // Interpretation: An ExpVal represents the value of an expression.
    -    
    -    interface ExpVal {
    -    
    -        // Returns true iff this ExpVal is a boolean, integer, or
    -        // function (respectively).
    -    
    -        boolean isBoolean();
    -        boolean isInteger();
    -        boolean isFunction();
    -    
    -        // Precondition: the corresponding predicate above is true.
    -        // Returns this.
    -        // (These methods amount should eliminate most casts.)
    -    
    -        boolean asBoolean();
    -        long asInteger();
    -        FunVal asFunction();
    -    }
    -  
    -
    -    // A FunVal is an object of any class that implements the FunVal interface.
    -    //
    -    // Interpretation: A FunVal represents the value of a lambda expression.
    -    
    -    import java.util.Map;
    -    
    -    interface FunVal extends ExpVal {
    -    
    -        // Returns the lambda expression from which this function was created.
    -    
    -        LambdaExp code();
    -    
    -        // Returns the environment that maps the free variables of that
    -        // lambda expression to their values.
    -    
    -        Map<String,ExpVal> environment();
    -    }
    -  
    -
    -

    - We have divided that problem into two parts. - In the first part, you will implement the abstract data types - for definitions, expressions, and expression values, - and define a public class that defines - public static factory methods for those types. - In the second part, you will define a public class that - defines a public static method for running - any given program of the language on any given inputs. -

    -
      -
    1. - Download and unpack the - set10.tgz file - we are giving you. -

      - Inside that set10 directory, - define another file named Asts.java - that defines a class named Asts - that defines the following public static methods: -

      -
      -        // Static factory methods for Def
      -        
      -        // Returns a Def with the given left and right hand sides.
      -        
      -        public static Def def (String id1, Exp rhs) { ... }
      -        
      -        // Static factory methods for Exp
      -        
      -        // Returns an ArithmeticExp representing e1 op e2.
      -        
      -        public static ArithmeticExp arithmeticExp (Exp e1, String op, Exp e2) { ... }
      -        
      -        // Returns a CallExp with the given operator and operand expressions.
      -        
      -        public static CallExp callExp (Exp operator, List<Exp> operands) { ... }
      -        
      -        // Returns a ConstantExp with the given value.
      -        
      -        public static ConstantExp constantExp (ExpVal value) { ... }
      -        
      -        // Returns an IdentifierExp with the given identifier name.
      -        
      -        public static IdentifierExp identifierExp (String id) { ... }
      -        
      -        // Returns an IfExp with the given components.
      -        
      -        public static IfExp ifExp (Exp testPart, Exp thenPart, Exp elsePart) { ... }
      -        
      -        // Returns a LambdaExp with the given formals and body.
      -        
      -        public static LambdaExp lambdaExp (List<String> formals, Exp body) { ... }
      -        
      -        // Static factory methods for ExpVal
      -        
      -        // Returns a value encapsulating the given boolean.
      -        
      -        public static ExpVal expVal (boolean b) { ... }
      -        
      -        // Returns a value encapsulating the given (long) integer.
      -        
      -        public static ExpVal expVal (long n) { ... }
      -        
      -        // Returns a value encapsulating the given lambda expression
      -        // and environment.
      -        
      -        public static FunVal expVal (LambdaExp exp, Map<String,ExpVal> env) { ... }
      -        
      -        // Static methods for creating short lists
      -        
      -        public static <X> List<X> list (X x1) { ... }
      -        
      -        public static <X> List<X> list (X x1, X x2) { ... }
      -        
      -        public static <X> List<X> list (X x1, X x2, X x3) { ... }
      -        
      -        public static <X> List<X> list (X x1, X x2, X x3, X x4) { ... }
      -      
      -
    2. -
    3. - Inside your set10 directory, - include another file named Programs.java - that defines a Programs class - that defines the following public static method: -
      -        public static ExpVal run (List<Def> pgm, List<ExpVal> inputs) {
      -            ...
      -        }
      -      
      -

      - Here is an example, which should print 120: -

      -
      -        // fact (n) if n = 0 then 1 else n * fact (n - 1) fi
      -        
      -        Exp exp1
      -            = Asts.arithmeticExp (Asts.identifierExp ("n"),
      -                                  "MINUS",
      -                                  Asts.constantExp (Asts.expVal (1)));
      -        Exp call1
      -            = Asts.callExp (Asts.identifierExp ("fact"),
      -                            Asts.list (exp1));
      -        Exp testPart
      -            = Asts.arithmeticExp (Asts.identifierExp ("n"),
      -                                  "EQ",
      -                                  Asts.constantExp (Asts.expVal (0)));
      -        Exp thenPart
      -            = Asts.constantExp (Asts.expVal (1));
      -        Exp elsePart
      -            = Asts.arithmeticExp (Asts.identifierExp ("n"),
      -                                  "TIMES",
      -                                  call1);
      -        Def def1
      -            = Asts.def ("fact",
      -                        Asts.lambdaExp (Asts.list ("n"),
      -                                        Asts.ifExp (testPart,
      -                                                    thenPart,
      -                                                    elsePart)));
      -        ExpVal result = Programs.run (Asts.list (def1),
      -                                      Asts.list (Asts.expVal (5)));
      -        System.out.println (result.asInteger());
      -      
      -
    4. -
    +
      +
    1. + (Player) +
      +

      + For this first part of Problem Set 10, you will define + a public class named Players in a file named + Players.java. + That class will define a public static factory method + named make that takes a String + as its one and only argument and returns a Player + whose name is the given string. +

      +
    2. +
    3. + (Roster) +
      +

      + For this second part of Problem Set 10, you will define + a public class named Rosters in a file named + Rosters.java. + That class will define a public static factory method + named empty that takes no arguments + and returns an empty roster. +

      +
      + HINT: iterator() methods are often implemented + by creating an object of some predefined class and + then creating the desired iterator by + calling that object's iterator method. +
      +
    4. +
    + + + diff --git a/ProblemSets/ps10.tgz b/ProblemSets/ps10.tgz new file mode 100644 index 0000000..5b30be5 Binary files /dev/null and b/ProblemSets/ps10.tgz differ diff --git a/ProblemSets/ps10.zip b/ProblemSets/ps10.zip new file mode 100644 index 0000000..f1c3fc3 Binary files /dev/null and b/ProblemSets/ps10.zip differ diff --git a/ProblemSets/ps11.html b/ProblemSets/ps11.html index 7fb88c5..0a4e0ac 100644 --- a/ProblemSets/ps11.html +++ b/ProblemSets/ps11.html @@ -14,7 +14,7 @@ + href="../cs5010.css" /> @@ -25,247 +25,428 @@

    CS 5010: Problem Set 11 -

    +

    - Out: Monday, 3 April 2017 + Out: Monday, 27 November 2017
    - Due: Monday, 10 April 2017 at 6pm -
    - Corrected: Monday, 3 April 2017 -
    - Corrected: Tuesday, 4 April 2017: -

      -
    • - you may use imports seen in Java files we give you -
    • -
    • - corrected concrete syntax - (semicolon is separator, not terminator) -
    • -
    • - set11parserV2 replaces set11parser -
    • -
    -

    -
    + Due: Monday, 4 December 2017 at 6pm local time +

    +

    - This is a - - pair programming - - assignment. You are required to - complete this problem set in collaboration with your assigned - partner, but neither of you are allowed to + This is an individual assignment. You are not allowed to discuss this problem set with any other person. You are also not allowed to search for or to view any solutions to similar problems that may be available on the World-Wide Web or in other resources that might otherwise have been available to you. -

    + (As always, however, you are encouraged to consult the + official documentation for the programming language you + are using, which will be especially relevant to this + problem set.) +

    - We have created a repository for you and your partner to use. -

    + The main purpose of this problem set is to give you practice + with higher-order functions in Java. +

    - In those repositories, we have created files named - ID1-log.txt and - ID2-log.txt for you to use when - filing work session reports, as in previous problem sets. - You and your partner are required to push your files at - the end of every work session. - (You may push your files several times during - a work session, but we do not require you to do so.) -

    + We will test your program using Java 8, + which is the version of Java installed on CCIS Linux machines. + You will therefore want to use Java 8 when developing and + testing your program. +

    - At the end of every work session, you are required to update - your log file to record the time you spent in that work session. - (Please do not include the time you spent in any previous work - sessions, as those times will already have been recorded in - previous versions of your log file.) - If both of you work together during a work session, both of - you must update your log files, recording only the time you - spent working. Do not include your partner's time in - your log file, but be sure to push the updated versions of - both log files. -

    -
    + For these problems, we are giving you the following files: +

    +
      +
    • + Player.java +
    • +
    • + RosterWithStream.java +
    • +
    +

    + You must not change those files in any way. +

    - In the first part of this problem set, - you will define a Programs.main method - that reads a ps11 program from a file - specified on the command line, parses that program, - and runs it on one or more inputs specified on the - command line, printing the result computed by the program. - That should make it easier for you to finish debugging - the interpreter you wrote in Problem Set 10. -

    + Part 1 of this problem set asks you to create + two more files named + Players.java and + RosterWithStreams.java. + Part 2 asks you to create a + TestRosterWithStream.java file. + All of those files must be in the default package. + In other words, your Java files should not contain any + package declarations. +

    - In the second part of this problem set, - you will implement a simple static analysis: - given the name of a file containing a ps11 program, - return a set containing the names of all undefined variables - that are referenced anywhere in the program. -

    + The Player interface we are giving you for + this problem set is the same as it was in Problem Set 10. + If your Players.java file from Problem Set 10 + was correct, then you can use it for Problem Set 11. + If it was incorrect, you'll have to repair it for Problem Set 11. +

    - You must use Java 8 for this assignment. - All of your code must reside within the default package. - You may use/import anything in the - java.lang and java.util - packages, - - and you may import the specific things imported by - the Java files we are giving you as a hint, - - but you are not allowed to use any other packages. -

    + You are free to create additional files. + When we test your submission, we will compile all of the + Java files in your set11 directory using the + following command: +

    +
    +      javac *.java
    +
    +

    + You should start by downloading the two files we are giving you, + unpacking them into a set11 directory, + and pushing that directory to your GitHub repository. +

    +

    + We are giving you a choice of two formats in which to download + the files we are giving you. Both of these links will unpack + to the same set11 directory containing exactly + the same Java files: +

    + +

    + Remember that you must follow the design recipe, which is a + process, not a list of deliverables. +

    +

    + Be sure to fill out a + work session report + at the end of each work session. + Be sure to report only the hours + spent in that work session; + do not report the cumulative time. + Tell git to add your work session report + to the files you will commit, + and then commit and push (sync) that report in addition to + committing and pushing your entire set11 directory. + Do this at the end of every work session. +

    +
    +

    + This problem set asks you to implement two abstract data types, + Player and RosterWithStream, + and to write a main method that tests those data types. + The Player ADT is the same as in Problem Set 10. + The RosterWithStream ADT is similar to the + Roster ADT of Problem Set 10, + but it adds a stream() method and changes + the return types of several other methods from + Roster to RosterWithStream. + (That is why RosterWithStream cannot just + extend the Roster interface.) +

    +

    + To make it easier to consider several similar rosters, the + RosterWithStream ADT is immutable. + The Player ADT is mutable, however, because an + injury, trade, or some other change to a player's status should + be propagated immediately to all rosters that use the player. +

    +
    +      // A Player is an object of any class that implements the Player interface.
    +      //
    +      // A Player object represents a member of a team.
    +      // Player objects are mutable because their status can change without
    +      // changing the identity of the Player.
    +      // 
    +      // If p1 and p2 are players, then p1.equals(p2) if and only if
    +      // p1 and p2 are the same object (i.e. (p1 == p2), p1 and p2
    +      // have the same name and status, and changing the status of p1
    +      // necessarily changes the status of p2 in the same way).
    +      //
    +      // If p is a player, then p.hashCode() always returns the same
    +      // value, even after the player's status is changed by calling
    +      // one of the last three methods listed below.
    +      //
    +      // If p1 and p2 are players with distinct names, then
    +      // p1.toString() is not the same string as p2.toString().
    +      //
    +      // Players.make(String name) is a static factory method that returns
    +      // a player with the given name who is (initially) available.
    +      
    +      interface Player {
    +      
    +          // Returns the name of this player.
    +          // Example:
    +          //     Players.make("Gordon Wayhard").name()  =>  "Gordon Wayhard"
    +      
    +          String name ();
    +      
    +          // Returns true iff this player is
    +          //     under contract, and
    +          //     not injured, and
    +          //     not suspended
    +          // Example:
    +          //     Player gw = Players.make ("Gordon Wayhard");
    +          //     System.out.println (gw.available());  // prints true
    +          //     gw.changeInjuryStatus (true);
    +          //     System.out.println (gw.available());  // prints false
    +      
    +          boolean available ();
    +      
    +          // Returns true iff this player is under contract (employed).
    +          // Example:
    +          //     Player ih = Players.make ("Isaac Homas");
    +          //     System.out.println (ih.underContract());  // prints true
    +          //     ih.changeContractStatus (false);
    +          //     System.out.println (ih.underContract());  // prints false
    +          //     ih.changeContractStatus (true);
    +          //     System.out.println (ih.underContract());  // prints true
    +      
    +          boolean underContract ();
    +      
    +          // Returns true iff this player is injured.
    +      
    +          boolean isInjured ();
    +      
    +          // Returns true iff this player is suspended.
    +      
    +          boolean isSuspended ();
    +      
    +          // Changes the underContract() status of this player
    +          // to the specified boolean.
    +      
    +          void changeContractStatus (boolean newStatus);
    +      
    +          // Changes the isInjured() status of this player
    +          // to the specified boolean.
    +      
    +          void changeInjuryStatus (boolean newStatus);
    +      
    +          // Changes the isSuspended() status of this player
    +          // to the specified boolean.
    +      
    +          void changeSuspendedStatus (boolean newStatus);
    +      }
    +
    +
    +      // A RosterWithStream is an object of any class that implements
    +      // the RosterWithStream interface defined below.
    +      //
    +      // A RosterWithStream object represents a set of players.
    +      //
    +      // RosterWithStream objects are immutable, but all players on a
    +      // RosterWithStream have mutable status, which can affect the
    +      // values returned by the readyCount() and readyRoster() methods.
    +      //
    +      // If r is a RosterWithStream object, then
    +      // r.iterator() generates the players of r in alphabetical order
    +      //
    +      // If r1 and r2 are RosterWithStream objects, then r1.equals(r2)
    +      // if and only if
    +      // every player on roster r1 is also on roster r2, and
    +      // every player on roster r2 is also on roster r1.
    +      //
    +      // If r is a roster, then r.hashCode() always returns the same
    +      // value, even if r has some players whose status changes.
    +      //
    +      // If r1 and r2 are rosters of different sizes, then
    +      // r1.toString() is not the same string as r2.toString().
    +      //
    +      // RosterWithStreams.empty() is a static factory method that returns a
    +      // RosterWithStream with no players.
    +      
    +      import java.util.stream.Stream;
    +      
    +      interface RosterWithStream extends Iterable<Player> {
    +      
    +          // Returns a roster consisting of the given player together
    +          // with all players on this roster.
    +          // Example:
    +          //     r.with(p).with(p)  =>  r.with(p)
    +      
    +          RosterWithStream with (Player p);
    +      
    +          // Returns a roster consisting of all players on this roster
    +          // except for the given player.
    +          // Examples:
    +          //     RosterWithStreams.empty().without(p)  =>  RosterWithStreams.empty()
    +          //     r.without(p).without(p)     =>  r.without(p)
    +      
    +          RosterWithStream without (Player p);
    +      
    +          // Returns true iff the given player is on this roster.
    +          // Examples:
    +          //
    +          //     RosterWithStreams.empty().has(p)  =>  false
    +          //
    +          // If r is any roster, then
    +          //
    +          //     r.with(p).has(p)     =>  true
    +          //     r.without(p).has(p)  =>  false
    +      
    +          boolean has (Player p);
    +      
    +          // Returns the number of players on this roster.
    +          // Examples:
    +          //
    +          //     RosterWithStreams.empty().size()  =>  0
    +          //
    +          // If r is a roster with r.size() == n, and r.has(p) is false, then
    +          //
    +          //     r.without(p).size()          =>  n
    +          //     r.with(p).size()             =>  n+1
    +          //     r.with(p).with(p).size()     =>  n+1
    +          //     r.with(p).without(p).size()  =>  n
    +      
    +          int size ();
    +      
    +          // Returns the number of players on this roster whose current
    +          // status indicates they are available.
    +      
    +          int readyCount ();
    +      
    +          // Returns a roster consisting of all players on this roster
    +          // whose current status indicates they are available.
    +      
    +          RosterWithStream readyRoster ();
    +      
    +          // Returns an iterator that generates each player on this
    +          // roster exactly once, in alphabetical order by name.
    +      
    +          Iterator<Player> iterator ();
    +      
    +          // Returns a sequential Stream with this RosterWithStream
    +          // as its source.
    +          // The result of this method generates each player on this
    +          // roster exactly once, in alphabetical order by name.
    +          // Examples:
    +          //
    +          //     RosterWithStreams.empty().stream().count()  =>  0
    +          //
    +          //     RosterWithStreams.empty().stream().findFirst().isPresent()
    +          //         =>  false
    +          //
    +          //     RosterWithStreams.empty().with(p).stream().findFirst().get()
    +          //         =>  p
    +          //
    +          //     this.stream().distinct()  =>  this.stream()
    +          //
    +          //     this.stream().filter((Player p) -> p.available()).count()
    +          //         =>  this.readyCount()
    +      
    +          Stream<Player> stream ();
    +      }
    +

    -
    -

    - Problem Specification -

    -

    - In Problem Set 10, you wrote an interpreter for - a simple functional programming language. -

    -

    - For Problem Set 11, we are going to change the concrete syntax - - by making semicolon a separator rather than a terminator, and - - by eliminating the fi token that terminated - if expressions in the concrete syntax given - in Problem Set 10. For Problem Set 11, the concrete syntax is: -

    -
    -    <pgm>     ::=  <defn>
    -              ::=  <defn> ; <pgm>
    -    <defn>    ::=  <id> = <const>
    -              ::=  <id> (<formals>) <expr>
    -    <const>   ::=  true 
    -              ::=  false
    -              ::=  <int>
    -    <lambda>  ::=  (λ ( <formals> ) <expr>)
    -    <expr>    ::=  <const>
    -              ::=  <id>
    -              ::=  <lambda>
    -              ::=  <arith>
    -              ::=  <call>
    -              ::=  <if>
    -              ::=  ( <expr> )
    -    <arith>   ::=  <expr> <op> <expr>
    -    <call>    ::=  <expr> (<exprs>)
    -    <if>      ::=  if <expr> then <expr> else <expr>
    -    
    -    <op>      ::=  < | = | > | + | - | *
    -    
    -    <formals>  ::=  <id>
    -               ::=  <id> , <formals>
    -    <exprs>    ::=  <expr>
    -               ::=  <expr> , <exprs>
    -    
    -    <int> and <id> are described by regular expressions:
    -    
    -        digit digit*
    -    
    -        letter (letter | digit)*
    -  
    -

    - That change to the concrete syntax should not affect any code - code you wrote for Problem Set 10, because your interpreter - used abstract syntax, which remains the same in Problem Set 11. -

    -

    - The concrete syntax we use will also allow comments, which - start with the # character and extend through - the end of the line. -

    -

    - The context-free grammar shown above is ambiguous, - but it can be converted into an unambiguous grammar - that generates the same set of programs. - The unambiguous grammar we will use as the official - concrete syntax is the - - LL(1) grammar - - given in the cfg.pg file within the - - set11parser directory - - we are giving you as a hint for part 1 of this problem set. - That directory contains a README file that - describes the files in that directory. - You should read that README file before you start to work - on this problem set. -

    -
    -

    - If you did a good job on Problem Set 10, this problem set - will be easy. If the interpreter you wrote for Problem Set 10 - had problems, this problem set will give you a chance to fix - those problems. -

    -
      -
    1. - Copy the program you wrote for Problem Set 11 into a - directory named set11. - Add a definition of the following public static method to - the Programs class defined in your - Programs.java file: -
      -        // Runs the ps11 program found in the file named on the command line
      -        // on the integer inputs that follow its name on the command line,
      -        // printing the result computed by the program.
      -        //
      -        // Example:
      -        //
      -        //     % java Programs sieve.ps11 2 100
      -        //     25
      -        
      -        public static void main (String[] args) { ... }
      -      
      -

      - Hint: - We are giving you a - - directory of Java code - - that contains a - - recursive descent parser - - for ps11 programs. - The Scanner class defined in Scanner.java - defines several public static methods you may find helpful. -

      -
    2. -
    3. - Add a definition of the following public static method to - the Programs class defined in your - Programs.java file: -
      -        // Reads the ps11 program found in the file named by the given string
      -        // and returns the set of all variable names that occur free within
      -        // the program.
      -        //
      -        // Examples:
      -        //     Programs.undefined ("church.ps11")    // returns an empty set
      -        //     Programs.undefined ("bad.ps11")       // returns { "x", "z" }
      -        //
      -        //   where bad.ps11 is a file containing:
      -        // 
      -        //     f (x, y) g (x, y) (y, z);
      -        //     g (z, y) if 3 > 4 then x else f
      -        
      -        public static Set<String> undefined (String filename) { ... }
      -      
      -
    4. -
    +
      +
    1. + (RosterWithStream) +
      +

      + For this first part of Problem Set 11, you will define + a public class named Players in a file named + Players.java and + a public class named RosterWithStreams in a file named + RosterWithStreams.java +

      +

      + The Players class + will define a public static factory method + named make that takes a String + as its one and only argument and returns a Player + whose name is the given string. +

      +

      + The RosterWithStreams class + will define a public static factory method + named empty that takes no arguments + and returns an empty RosterWithStream. +

      +
      + HINT: You will probably find it worth your time to read + and to understand the + official Java documentation for the + stream methods of the + java.util.stream.StreamSupport + class. + Those stream methods are static factory methods + for creating Stream<T> objects. + You might also benefit from knowing that any class + that implements the Iterable<T> interface + (or any interface that extends Iterable<T>) + automatically defines a default spliterator() + method that calls the iterator() method + of that class and uses the Iterator<T> + result of that call to create + an analogous Spliterator<T>. +
      +
    2. +
    3. + (Testing) +
      +

      + For this second part of Problem Set 11, you will define + a public class named + TestRosterWithStream in a file named + TestRosterWithStream.java. + That class will define a public static main method + that tests the code you wrote in part 1. +

      +

      + Testing the stream method of the + RosterWithStream ADT + ought to involve testing all of the methods supported + by the Stream<Player> objects + that will be returned + by that method. Some of those methods ought to be + tested by more than one test. + (The allMatch and anyMatch + methods, for example, both ought to be tested in a + situation for which they return true and in a situation + for which they return false.) +

      +

      + That could turn out to be a lot of testing. + If you write beautiful code for part 1, + making appropriate use of Java's pre-defined default methods, + then some of that testing may be less important because any + mistakes in the default methods will probably have the same + root causes as mistakes that can be found by testing some of + the more basic methods. + Course staff will therefore give special attention to + the tests you write for the following methods: +

      +
      +          boolean       allMatch(Predicate<? super T> predicate)
      +          boolean       anyMatch(Predicate<? super T> predicate)
      +          long          count()
      +          Stream<T>     distinct()
      +          Stream<T>     filter(Predicate<? super T> predicate)
      +          Optional<T>   findAny()
      +          Optional<T>   findFirst()
      +          void          forEach(Consumer<? super T> action)
      +          <R> Stream<R> map(Function<? super T,? extends R> mapper)
      +          T             reduce(T identity, BinaryOperator<T> accumulator)
      +          Stream<T>     skip(long n)
      +          Object[]      toArray()
      +
      +
    4. +
    + + + diff --git a/ProblemSets/set09.tgz b/ProblemSets/set09.tgz new file mode 100644 index 0000000..40f3e06 Binary files /dev/null and b/ProblemSets/set09.tgz differ diff --git a/ProblemSets/set09.zip b/ProblemSets/set09.zip new file mode 100644 index 0000000..38df964 Binary files /dev/null and b/ProblemSets/set09.zip differ diff --git a/ProblemSets/set10.tgz b/ProblemSets/set10.tgz index 5880cbd..5b30be5 100644 Binary files a/ProblemSets/set10.tgz and b/ProblemSets/set10.tgz differ diff --git a/ProblemSets/set10.zip b/ProblemSets/set10.zip new file mode 100644 index 0000000..f1c3fc3 Binary files /dev/null and b/ProblemSets/set10.zip differ diff --git a/ProblemSets/set11.tgz b/ProblemSets/set11.tgz new file mode 100644 index 0000000..5b50bc1 Binary files /dev/null and b/ProblemSets/set11.tgz differ diff --git a/ProblemSets/set11.zip b/ProblemSets/set11.zip new file mode 100644 index 0000000..2a7f077 Binary files /dev/null and b/ProblemSets/set11.zip differ diff --git a/ProblemSets/set11parser.tgz b/ProblemSets/set11parser.tgz deleted file mode 100644 index 6a06cce..0000000 Binary files a/ProblemSets/set11parser.tgz and /dev/null differ diff --git a/ProblemSets/set12.tgz b/ProblemSets/set12.tgz deleted file mode 100644 index 471b9bd..0000000 Binary files a/ProblemSets/set12.tgz and /dev/null differ diff --git a/Slides/Common Slides for CS 5010.pptx b/Slides/Common Slides for CS 5010.pptx index 4f28cac..c4f865f 100644 Binary files a/Slides/Common Slides for CS 5010.pptx and b/Slides/Common Slides for CS 5010.pptx differ diff --git a/Slides/Lesson 12.1 The Last Lecture.pptx b/Slides/Lesson 12.1 The Last Lecture.pptx index 129a3fd..8d47e1f 100644 Binary files a/Slides/Lesson 12.1 The Last Lecture.pptx and b/Slides/Lesson 12.1 The Last Lecture.pptx differ diff --git a/Slides/Lesson 8.1 General Recursion.pptx b/Slides/Lesson 8.1 General Recursion.pptx index ed389ec..3bc5ea5 100644 Binary files a/Slides/Lesson 8.1 General Recursion.pptx and b/Slides/Lesson 8.1 General Recursion.pptx differ diff --git a/Slides/Lesson 8.2 Binary Search.pptx b/Slides/Lesson 8.2 Binary Search.pptx index ebb9802..73f43d3 100644 Binary files a/Slides/Lesson 8.2 Binary Search.pptx and b/Slides/Lesson 8.2 Binary Search.pptx differ diff --git a/Slides/Lesson 8.3 Binary Search - 2016.pptx b/Slides/Lesson 8.3 Binary Search - 2016.pptx new file mode 100644 index 0000000..65471c2 Binary files /dev/null and b/Slides/Lesson 8.3 Binary Search - 2016.pptx differ diff --git a/Slides/Lesson 9.5 The Design Recipe Using Classes.pptx b/Slides/Lesson 9.5 The Design Recipe Using Classes.pptx index b084bb4..2aecd34 100644 Binary files a/Slides/Lesson 9.5 The Design Recipe Using Classes.pptx and b/Slides/Lesson 9.5 The Design Recipe Using Classes.pptx differ diff --git a/Slides/Lesson 9.6 The Design Recipe Using Classes.pptx b/Slides/Lesson 9.6 The Design Recipe Using Classes.pptx new file mode 100644 index 0000000..4c01252 Binary files /dev/null and b/Slides/Lesson 9.6 The Design Recipe Using Classes.pptx differ diff --git a/TODO b/TODO index 532f835..52dba8d 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -Items for Will: +XXItems for Will: / I Am Here? / PS 00 diff --git a/index.html b/index.html index c355df9..982ddff 100644 --- a/index.html +++ b/index.html @@ -387,12 +387,12 @@

    - Defining OO Data with Interfaces and Classes + Defining OO Data with Interfaces and Classes, Part I - + 09 @@ -408,14 +408,14 @@

    13 Nov - + - Sharing Implementations with Inheritance + Interfaces and Classes II - + 10 @@ -451,14 +451,14 @@

    27 Nov - + - Using Objects with Mutable State + Sharing Implementations using Inheritance - + 11 (Last Problem Set) @@ -474,9 +474,9 @@

    4 Dec - + - Efficiency, Part 2 + Special Bonus Content
    (come and see!)
    @@ -527,5 +527,6 @@

    +