;;; oop ;;; Copyright 1984-2017 Cisco Systems, Inc. ;;; ;;; Licensed under the Apache License, Version 2.0 (the "License"); ;;; you may not use this file except in compliance with the License. ;;; You may obtain a copy of the License at ;;; ;;; http://www.apache.org/licenses/LICENSE-2.0 ;;; ;;; Unless required by applicable law or agreed to in writing, software ;;; distributed under the License is distributed on an "AS IS" BASIS, ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;;; See the License for the specific language governing permissions and ;;; limitations under the License. (mat oop (begin (import (oop)) (define-syntax seq-list (lambda (x) (import (only scheme list)) (syntax-case x () [(_ e ...) (with-syntax ([(t ...) (generate-temporaries #'(e ...))]) #'(let* ([t e] ...) (list t ...)))]))) (define true? (lambda (x) (eq? x #t))) #t) (begin (define-class ( a1) () (ivars [x1 a1]) (methods [m1 (q) (list self x1 q)] [m2 () x1])) #t) (error? ; incorrect argument count (make-)) (error? ; incorrect argument count (make- 1 2)) (begin (define i1 (make- 3)) #t) (equal? (cdr (m1 i1 4)) '(3 4)) (eq? (car (m1 i1 4)) i1) (error? ; incorrect argument count (m1 i1)) (error? ; incorrect argument count (m1 i1 4 5)) (error? ; m1 not applicable to 17 (m1 17 4)) (error? ; not bound (-x1 i1)) (error? ; not bound (-x1-set! i1 17)) ; no longer an error to duplicate x1 (begin (define x1 'outer-x1) (define x3 'outer-x3) (define-class ( b1 b2) ( (+ b1 b2)) (ivars [x1 b1] [x2 b2]) (methods [m1 (q) (vector self x1 q)] [m3 (s t) (list s t x1 x2)] [m4 () x3])) (define i2 (make- 10 4)) #t ) (equal? (m2 i2) 14) (equal? (m3 i2 'kurds 'weigh) '(kurds weigh 10 4)) (eq? (m4 i2) 'outer-x3) (begin (define-class ( b1 b2) ( (+ b1 b2)) (ivars [x2 b1] [x3 b2]) (methods [m1 (q) (vector self x2 q)] [m4 () x1] [m3 (s t) (list s t x1 x2 x3)])) (define i2 (make- 4 5)) #t) (eq? (m4 i2) 'outer-x1) (eq? (vector-ref (m1 i2 6) 0) i2) (equal? (vector-ref (m1 i2 6) 1) 4) (equal? (vector-ref (m1 i2 6) 2) 6) (begin (define-class ( x) () (ivars [x x]) (methods [c1 (a) (make- a)])) #t) ((lambda (x) (? x)) (c1 (make- 4) 5)) (eq? (let () (define-class ( x) () (ivars [x x]) (methods [c1 (a) (make- a)] [c2 () x])) (c2 (c1 (make- 44) 87))) 87) (begin (define-class (foo x) () (ivars [x x]) (methods [hit () x] [hit (y) (set! x (+ x y))])) #t) (equal? (let ([a (make-foo 1)]) (let ((b (hit a))) (hit a 17) (list b (hit a)))) '(1 18)) (error? ; invalid arity for hit (define-class (bar) (foo 1) (methods [hit (y z) (list y z)]))) ; test variable arity methods (equal? (let () (define-class (foo) () (methods [test (a . b) (list 'test a b)])) (test (make-foo) 1 2 3 4 5)) '(test 1 (2 3 4 5))) (equal? (let () (define-class (foo) () (methods [test (a . b) (list 'test a b)])) (define-class (bar) (foo) (methods [test (x . y) (list 'bar x y (super 'p 'd 'q 'r 's 't 'u))])) (test (make-bar) 1 2 3 4 5 6 7)) '(bar 1 (2 3 4 5 6 7) (test p (d q r s t u)))) (equal? (let () (define-class (foo x) () (ivars [x x]) (methods [ping () x] [ping (v) (set! x v)])) (define-class (bar x) (foo x) (methods [ping () super] ; return super method [ping (v) (super (+ (super) v))])) (let ([x (make-foo 1)] [y (make-bar 10)]) (let ([before-x (ping x)] [before-y ((ping y))]) (ping x 100) (ping y 100) (let ([after-x (ping x)] [after-y ((ping y))]) ((ping y) 76) (list before-x before-y after-x after-y ((ping y))))))) '(1 10 100 110 76)) (equal? (let () (define-class (foo) () (methods [chow x (cons 'foo x)])) (define-class (bar) (foo) (methods [chow x (apply super 'bar x)])) (list (chow (make-foo) 1 2 3) (chow (make-bar) 4 5 6))) '((foo 1 2 3) (foo bar 4 5 6))) ; Verify that first-class super knows all arities of corresponding method. (equal? (let () (define-class (foo) () (methods [chow (mein) (list 'foo 'chow-1 mein)] [chow (a b) (list 'foo 'chow-2 a b)])) (define-class (bar) (foo) (methods [chow (a b) super])) (let ([sup (chow (make-bar) 'ignore1 'ignore2)]) (list (sup 'mane) (sup "ay" "bee")))) '((foo chow-1 mane) (foo chow-2 "ay" "bee"))) ; Verify that we don't override method unless its generic is visible, ; i.e., we get a new method of the same name (equal? (let () (module (foo (alpha bar)) (define-class (foo) () (methods [bar () 'foobar])) (define-syntax alpha (identifier-syntax bar))) (define-class (baz) (foo) (methods [bar () 'bazbar])) (let ([x (make-baz)]) (list (alpha x) (bar x)))) '(foobar bazbar)) ; Verify that we can't send super unless method's generic is visible. (error? ; no inherited bar method (super) (let () (module (foo (alpha bar)) (define-class (foo) () (methods [bar () 'foobar])) (define-syntax alpha (identifier-syntax bar))) (define-class (baz) (foo) (methods [bar () (super)])) (make-baz))) ; Verify that we can't define a generic for a method with the same name ; as an interface method, i.e., supply an implementation of an ; interface-inherited method with the wrong arity (begin (define-interface bonk [whack (a mole)]) #t) (error? ; invalid arity for whack (define-class (pewter) () (implements bonk) (methods [whack (e) "method w/ same name as interface method, but diff arity"] [whack (o no) "method matches interface method"]))) ; more elaborate verification that we can't define a generic for a method ; with the same name as an interface method, i.e., supply an implementation ; of an interface-inherited method with the wrong arity (begin (define-interface bark [ham ()] [spam (y)]) #t) (error? ; invalid arity for whack (or spam) (define-class (platinum) () (implements bark bonk) (methods [ham () "and cheese"] [spam () "spam"] [spam (y) "spam"] [xspam (x) "xspam"] [whack (e) "method w/ same name as interface method, but diff arity"] [whack (o no) "method matches interface method"]))) (error? ; invalid arity for whack (or spam) (define-class (platinum) () (implements bonk bark) (methods [ham () "and cheese"] [spam () "spam"] [spam (y) "spam"] [xspam (x) "xspam"] [whack (e) "method w/ same name as interface method, but diff arity"] [whack (o no) "method matches interface method"]))) (error? ; invalid arity for spam (or whack) (define-class (platinum) () (implements bark bonk) (methods [whack (e) "method w/ same name as interface method, but diff arity"] [whack (o no) "method matches interface method"] [ham () "and cheese"] [spam () "spam"] [spam (y) "spam"] [xspam (x) "xspam"]))) (error? ; invalid arity for spam (or whack) (define-class (platinum) () (implements bonk bark) (methods [whack (e) "method w/ same name as interface method, but diff arity"] [whack (o no) "method matches interface method"] [ham () "and cheese"] [spam () "spam"] [spam (y) "spam"] [xspam (x) "xspam"]))) (begin (define-interface i1 [fish (fry)]) (define-interface i2 [rats (around)]) #t) (error? ; fish not applicable to 3 (fish 3 4)) (error? ; rats not applicable to 3 (rats 3 4)) (error? ; fish not applicable to # (let () (define-record frob ()) (record-writer (type-descriptor frob) (lambda (x p wr) (display "#" p))) (fish (make-frob) 4))) (error? ; no implementation of interface method rats (define-class ( x) () (implements i1 i2) (ivars [x (* x x)]) (methods [fish (fry) (list fry x)] [run (around) (cons around x)] [x! (v) (set! x (* v v))]))) (equal? (let () (define-class ( x) () (implements i1 i2) (ivars [x (* x x)]) (methods [fish (fry) (list fry x)] [rats (around) (cons around x)] [x? () x] [x! (v) (set! x (* v v))])) (define d (make- 3)) (x! d 7) (list (x? d) (fish d "hi") (rats d "ih"))) '(49 ("hi" 49) ("ih" . 49))) (begin (define-class () () (methods [m1 () (define-class () () (methods [m2 () 14])) (* (m2 (make-)) 2)])) #t) (eqv? (m1 (make-)) 28) (equal? (let () (define (m2 x) "undefined") (module (c1 make-c1 m1 c1-friends) (module all (c1 make-c1 m1 m2) (define-class (c1) () (methods [m1 () "public"] [m2 () "protected"]))) (module c1-friends (m2) (import all)) (import all)) (module (make-c2 m3) (import c1-friends) (define-class (c2) (c1) (methods [m3 () (m2 self)]))) (module (make-c3 m4) (import c1-friends) (define-class (c3) () (methods [m4 (x) (m2 x)]))) (let ([x (make-c2)] [y (make-c3)]) (list (m1 x) (m2 x) (m3 x) (m4 y x)))) '("public" "undefined" "protected" "protected")) (equal? (let () (define (m2 x) "undefined") (module (c1 make-c1 m1 c2 make-c2 m3 make-c3 m4) (define-class (c1) () (methods [m1 () "public"] [m2 () "protected"])) (define-class (c2) (c1) (methods [m3 () (m2 self)])) (define-class (c3) () (methods [m4 (x) (m2 x)]))) (let ([x (make-c2)] [y (make-c3)]) (list (m1 x) (m2 x) (m3 x) (m4 y x)))) '("public" "undefined" "protected" "protected")) (true? (let ([f (lambda () (define-class (frap) ()) (cons make-frap frap?))]) ((cdr (f)) ((car (f)))))) (true? (let ([f (lambda () (define-class (frap) () (methods [m () 5])) (cons make-frap frap?))]) (not ((cdr (f)) ((car (f))))))) (true? (let ([f (lambda () (define-class (frap) ()) (cons make-frap frap?))] [g (lambda () (define-class (frap) ()) (cons make-frap frap?))]) (and (not ((cdr (f)) ((car (g))))) (not ((cdr (g)) ((car (f)))))))) (true? (let ([f (lambda () (define-class (#{frap |.O7*%gC?Sxs~2\\%|}) ()) (cons make-frap frap?))] [g (lambda () (define-class (#{frap |.O7*%gC?Sxs~2\\%|}) ()) (cons make-frap frap?))]) (and ((cdr (f)) ((car (g)))) ((cdr (g)) ((car (f))))))) (true? (let ([f (lambda () (define-class (#{frap |.TfvA+Ml1*u&?\\%|}) () (ivars [x 0])) (cons make-frap frap?))] [g (lambda () (define-class (#{frap |.TfvA+Ml1*u&?\\%|}) () (ivars [x 0])) (cons make-frap frap?))]) (and ((cdr (f)) ((car (g)))) ((cdr (g)) ((car (f))))))) (error? ; incompatible record type (let ([f (lambda () (define-class (#{frap |.Uo3>P+Wu9o=u\\%|}) () (ivars [x 0])) (cons make-frap frap?))] [g (lambda () (define-class (#{frap |.Uo3>P+Wu9o=u\\%|}) () (ivars [y 0])) (cons make-frap frap?))]) (and ((cdr (f)) ((car (g)))) ((cdr (g)) ((car (f))))))) (error? ; cannot specify gensym class-name with methods or interfaces (let ([f (lambda () (define-class (frap) () (methods [m1 () 5])) (cons make-frap frap?))] [g (lambda () (define-class (#{frap |.R@iB9FE~OXVz\\%|}) () (methods [m1 () 5])) (cons make-frap frap?))]) (and ((cdr (f)) ((car (g)))) ((cdr (g)) ((car (f))))))) (equal? (let () (define-class ( x) () (constructor frozwell-make) (predicate is-frozwell?)) (let ([frzwl (frozwell-make 3)]) (list (is-frozwell? frzwl) (is-frozwell? 17)))) '(#t #f)) (begin (define-class ( x) () (constructor frozwell-make) (predicate is-frozwell?)) #t) (equal? (let ([frzwl (frozwell-make 3)]) (list (is-frozwell? frzwl) (is-frozwell? 17))) '(#t #f)) (begin (library (L1) (export frozwell-make is-frozwell?) (import (chezscheme) (oop)) (define-class ( x) () (constructor frozwell-make) (predicate is-frozwell?))) #t) (equal? (let () (import (L1)) (let ([frzwl (frozwell-make 3)]) (list (is-frozwell? frzwl) (is-frozwell? 17)))) '(#t #f)) (error? ; invalid syntax (let () (import (L1)) )) (error? ; extra ivars clause (define-class (foo) () (ivars [x 0]) (ivars [y 1]) (methods [show () (values x y)]))) (error? ; extra methods clause (define-class (foo) () (ivars [x 0] [y 1]) (methods [show () (values x y)]) (methods [get-x () x]))) (begin (define-interface istud [cram (z)]) (define-class (fritz q) () (methods [fritz-x+ (y) (+ x y)] [cram (n) (set! x (+ x n))]) (predicate ?fritzy) (ivars [x (* q q)]) (constructor fritzit) (implements istud)) #t) (equal? (let ([w (fritzit 10)]) (cram w 50) (list (?fritzy w) (?fritzy 'fritzy) (fritz-x+ w 7))) '(#t #f 157)) (error? ; invalid assignment of immutable ivar x (define-class (blast x) () (ivars [immutable x x] [mutable y x]) (init (set! x (* x x))))) (error? ; invalid assignment of immutable ivar x (define-class (blast x) () (ivars [immutable x x] [mutable y x]) (methods [m (v) (set! x v)]))) (error? ; blast-x-set! not bound (let () (define-class (blast x) () (ivars [public immutable x x] [public mutable y x])) (define b (make-blast 17)) (blast-x-set! b (* (blast-x b) (blast-x b))) (blast-x b))) (equal? (let () (define-class (blast x) () (ivars [public immutable x x] [public mutable y x]) (init (set! y (* y y)))) (define b (make-blast 9)) (list (blast-x b) (blast-y b))) '(9 81)) (equal? (let () (define-class (blast x) () (ivars [public immutable x x] [public mutable y x]) (methods [m (v) (set! y v)])) (define b (make-blast 9)) (m b 35) (list (blast-x b) (blast-y b))) '(9 35)) (equal? (let () (define-class (blast x) () (ivars [public immutable x x] [public mutable y x])) (define b (make-blast 17)) (blast-y-set! b (* (blast-x b) (blast-x b))) (list (blast-x b) (blast-y b))) '(17 289)) (begin (define-class ( a1) () (ivars [public mupu1 (+ a1 1)] [public mutable mupu2 (+ a1 2)] [public immutable impu3 (+ a1 3)] [private mupr4 (+ a1 4)] [private mutable mupr5 (+ a1 5)] [private immutable impr6 (+ a1 6)] [private mupr7 (+ a1 7)] [private mutable mupr8 (+ a1 8)] [private immutable impr9 (+ a1 9)])) (define i1 (make- 10)) #t) (equal? (list (-mupu1 i1) (-mupu2 i1) (-impu3 i1)) '(11 12 13)) (equal? (begin (-mupu1-set! i1 'a) (-mupu2-set! i1 'b) (list (-mupu1 i1) (-mupu2 i1) (-impu3 i1))) '(a b 13)) (error? ; not bound -mupr4) (error? ; not bound -mupr5) (error? ; not bound -impr6) (error? ; not bound -mupr7) (error? ; not bound -mupr8) (error? ; not bound -impr9) (error? ; not bound -impu3-set!) (error? ; not bound -mupr4-set!) (error? ; not bound -mupr5-set!) (error? ; not bound -impr6-set!) (error? ; not bound -mupr7-set!) (error? ; not bound -mupr8-set!) (error? ; not bound -impr9-set!) (begin (define-class ( a1) ( (+ a1 10)) (ivars [public mupu1 (+ a1 1)] [mutable public mupu2 (+ a1 2)] [immutable public impu3 (+ a1 3)])) (define i2 (make- 10)) #t) (equal? (list (-mupu1 i2) (-mupu2 i2) (-impu3 i2) (-mupu1 i2) (-mupu2 i2) (-impu3 i2)) '(21 22 23 11 12 13)) (equal? (begin (-mupu1-set! i2 "hi") (-mupu2-set! i2 "there") (-mupu1-set! i2 "ye") (-mupu2-set! i2 "matey") (list (-mupu1 i2) (-mupu2 i2) (-impu3 i2) (-mupu1 i2) (-mupu2 i2) (-impu3 i2))) '("hi" "there" 23 "ye" "matey" 13)) (error? ; not bound -impu3-set!) (error? ; not applicable (-mupu1 i1)) (error? ; not applicable (-mupu1-set! i1 55)) (begin (define-class ( a1) ( (+ a1 10)) (ivars [public mupu1 (+ a1 1)] [public mutable mupu2 (+ a1 2)] [public immutable impu3 (+ a1 3)]) (prefix "s$")) (define i3 (make- 10)) #t) (equal? (list (-mupu1 i3) (-mupu2 i3) (-impu3 i3) (-mupu1 i3) (-mupu2 i3) (-impu3 i3) (s$mupu1 i3) (s$mupu2 i3) (s$impu3 i3)) '(31 32 33 21 22 23 11 12 13)) (equal? (begin (-mupu1-set! i3 'hi) (-mupu2-set! i3 'there) (-mupu1-set! i3 'ye) (-mupu2-set! i3 'matey) (s$mupu1-set! i3 'scaliwag) (s$mupu2-set! i3 'pirate) (list (-mupu1 i3) (-mupu2 i3) (-impu3 i3) (-mupu1 i3) (-mupu2 i3) (-impu3 i3) (s$mupu1 i3) (s$mupu2 i3) (s$impu3 i3))) '(hi there 33 ye matey 23 scaliwag pirate 13)) (error? ; not bound -impu1) (error? ; not bound s$impu3-set!) (error? ; not applicable (s$mupu1 i1)) (error? ; not applicable (s$mupu1-set! i1 55)) (error? ; not applicable (s$mupu1 i2)) (error? ; not applicable (s$mupu1-set! i2 55)) ;;; tests from Michael Lenaghan of frogware, Inc. (begin ;; simple init expression (define-class ( x y) () (ivars [x x] [y y] [z (* x y)]) (methods [method-1 () z])) ;; simple init expressions that depend ;; on previously computed values (define-class ( x y) () (ivars [x x] [y y] [z1 (* x y)] [z2 (* 2 z1)]) (methods [method-2 () z2])) ;; simple init proc (define-class ( x y) () (ivars [x x] [y y] [z 0]) (init (set! z (* x y))) (methods [method-3 () z])) ;; class and base class initialization can have ;; different arity (define-class ( x) ( x x)) ;; class and base class initialization can have ;; different arity and base class can use expressions (define-class ( x) ( x (* 2 x))) #t) (eqv? (let ([test (make- 5 10)]) (method-1 test)) 50) (eqv? (let ([test (make- 5 10)]) (method-2 test)) 100) (eqv? (let ([test (make- 5 10)]) (method-3 test)) 50) (eqv? (let ([test (make- 5)]) (method-1 test)) 25) (eqv? (let ([test (make- 5)]) (method-1 test)) 50) (begin ;; base class (define-class ( init-1) () (ivars [fld-1 init-1]) (methods [whoami () self] [method-1 () fld-1] [method-2 (x) (set! fld-1 x)])) ;; sub-class (define-class ( init-1 init-2) ( init-1) (ivars [fld-2 init-2]) (methods [method-3 () fld-2] [method-4 (x) (set! fld-2 x)])) ;; Note: The class can't use the method names ;; "method-3" and "method-4" because they're used by ;; . Chez OOP produces a "generic function" ;; for each method, and it looks like those functions ;; all have to belong to one line of the class inheritance ;; tree. ;; sub-class w/ overload (define-class ( init-1 init-2) ( init-1) (ivars [fld-2 init-2]) (methods [method-1 () (method-3a self)] [method-2 (x) (method-4a self x)] [method-3a () fld-2] [method-4a (x) (set! fld-2 x)])) ;; sub-class w/ overload & fields ;; if this is uncommented, uncomment test below #; (define-class ( init-1) ( init-1) (methods [method-3b () ;; this provides access to super-class fields (open-instance "" self) fld-1] [method-4b (x) ;; this provides access to super-class fields (open-instance "" self) (set! fld-1 x)])) ;; sub-class w/ overload & super (define-class ( init-1) ( init-1) (methods [method-1 () (string->symbol (string-append (symbol->string (super)) "!!!"))] [method-2 (x) (super (string->symbol (string-append (symbol->string x) "!!!")))])) ;; sub-class w/ variable arity (define-class ( init-1) ( init-1) (methods [method-5 () (method-1 self)] [method-5 (x) (method-2 self x)])) #t) (equal? (let ((test (make- 'hello))) (seq-list (eq? test (whoami test)) (method-1 test) (method-2 test 'goodbye) (method-1 test))) `(#t hello ,(void) goodbye)) (equal? (let ((test (make- 'hello 'hello-again))) (seq-list (method-1 test) (method-2 test 'goodbye) (method-1 test) (method-3 test) (method-4 test 'goodbye-again) (method-3 test))) `(hello ,(void) goodbye hello-again ,(void) goodbye-again)) (equal? (let ((test (make- 'hello 'hello-again))) (seq-list (method-1 test) (method-2 test 'goodbye-again) (method-1 test) (method-3a test) (method-4a test 'hello-again) (method-3a test))) `(hello-again ,(void) goodbye-again goodbye-again ,(void) hello-again)) #; (equal? (let ((test (make- 'hello))) (seq-list (method-1 test) (method-2 test 'goodbye) (method-1 test) (method-3b test) (method-4b test 'hello) (method-3b test))) `(hello ,(void) goodbye goodbye ,(void) hello)) (equal? (let ((test (make- 'hello))) (seq-list (method-1 test) (method-2 test 'goodbye) (method-1 test))) `(hello!!! ,(void) goodbye!!!!!!)) (equal? (let ((test (make- 'hello))) (seq-list (method-5 test) (method-5 test 'goodbye) (method-5 test))) `(hello ,(void) goodbye)) (begin ;; use class exported from module (module test-1 ( make- method-1) (define-class ( x) () (ivars [x x]) (methods [method-1 () x]))) #t) (eqv? (let () (import test-1) (method-1 (make- 3))) 3) (eqv? (let () (import test-1) (define-class ( x) ( x)) (method-1 (make- 3))) 3) (begin ;; use sub-class exported from module (module test-2 ( make- method-1) (import test-1) (define-class ( x) ( x))) #t) (eqv? (let () (import test-2) (method-1 (make- 3))) 3) (begin ;; use sub-class w/ overload exported from module (module test-3 (make- method-1) (import test-2) (define-class ( x) ( x) (ivars [x x]) (methods [method-1 () (* x x)]))) #t) (eqv? (let () (import test-1) (let ([test (make- 10)]) (method-1 test))) 10) (eqv? (let () (import test-2) (let ([test (make- 10)]) (method-1 test))) 10) (eqv? (let () (import test-3) (let ([test (make- 10)]) (method-1 test))) 100) (begin ;; base interface (define-interface <> [imethod-1 ()] [imethod-2 (x)]) ;; sub-interface (define-interface <> <> [imethod-3 ()] [imethod-4 (x)]) ;; base interface (define-interface <> [imethod-5 ()] [imethod-6 (x)]) ;; base class w/ base interface (define-class ( init-1) () (implements <>) (ivars [fld-1 init-1]) (methods [method-1 () 'method-1] [imethod-1 () fld-1] [imethod-2 (x) (set! fld-1 x)])) ;; sub-class w/ sub-interface (define-class ( init-1 init-2) ( init-1) (implements <>) (ivars [fld-2 init-2]) (methods [method-2 () 'method-2] [imethod-3 () fld-2] [imethod-4 (x) (set! fld-2 x)])) ;; sub-class w/ new method (define-class ( init-1 init-2) ( init-1 init-2) (ivars [fld-3 (+ init-1 init-2)]) (methods [method-3 () fld-3])) ;; base class w/ interfaces & new method (define-class ( init-1) () (implements <> <>) (ivars [fld-1 init-1]) (methods [imethod-1 () (* 2 fld-1)] [imethod-2 (x) (set! fld-1 x)] [imethod-5 () (* 4 fld-1)] [imethod-6 (x) (set! fld-1 x)] [method-4 () fld-1] [method-4! (x) (set! fld-1 x)])) #t) (equal? (let ((itest (make- 'hello))) (seq-list (method-1 itest) (imethod-1 itest) (imethod-2 itest 'goodbye) (imethod-1 itest))) `(method-1 hello ,(void) goodbye)) (eqv? (let ((itest (make- 'hello 'hello-again))) (method-2 itest)) 'method-2) (equal? (let ((itest (make- 'hello 'hello-again))) (seq-list (imethod-1 itest) (imethod-2 itest 'goodbye) (imethod-1 itest) (imethod-3 itest) (imethod-4 itest 'goodbye-again) (imethod-3 itest))) `(hello ,(void) goodbye hello-again ,(void) goodbye-again)) (eqv? (let ((itest (make- 5 10))) (method-3 itest)) 15) (equal? (let ((itest (make- 10))) (seq-list (imethod-1 itest) (imethod-5 itest) (method-4 itest) (method-4! itest 20) (imethod-1 itest) (imethod-5 itest) (method-4 itest))) `(20 40 10 ,(void) 40 80 20)) (begin ;; export interface from module (module test-1 (<> imethod-1 imethod-2) (define-interface <> [imethod-1 ()] [imethod-2 (v)])) ;; export sub-interface from module (module test-2 (<> imethod-3 imethod-4) (import test-1) (define-interface <> <> [imethod-3 ()] [imethod-4 (v)])) ;; use class w/ interface exported from module (module test-3 ( make- imethod-1 imethod-2) (import test-1) (define-class ( x) () (implements <>) (ivars [x x]) (methods [imethod-1 () x] [imethod-2 (v) (set! x v)]))) ;; use sub-class w/ interface exported from module (module test-4 ( make- imethod-1 imethod-2 imethod-3 imethod-4) (import test-2) (import test-3) (define-class ( x) ( x) (implements <>) (methods [imethod-3 () (* 2 (imethod-1 self))] [imethod-4 (v) (imethod-2 self (* 2 v))]))) ;; use sub-class w/ overload of interface methods exported from module (module test-5 (make- imethod-1 imethod-2 imethod-3 imethod-4) (import test-4) (define-class ( x) ( x) (methods [imethod-1 () (* 2 (super))] [imethod-3 () (* 2 (super))]))) ;; use sub-class w/ new methods exported from module (module test-6 (make- method-1) (import test-4) (define-class ( x) ( x) (ivars [x x]) (methods [method-1 () (* x x)]))) #t) (equal? (let () (import test-3) (let ([test (make- 10)]) (seq-list (imethod-1 test) (imethod-2 test 20) (imethod-1 test)))) `(10 ,(void) 20)) (equal? (let () (import test-4) (let ([test (make- 10)]) (seq-list (imethod-1 test) (imethod-2 test 20) (imethod-1 test) (imethod-3 test) (imethod-4 test 20) (imethod-3 test)))) `(10 ,(void) 20 40 ,(void) 80)) (equal? (let () (import test-5) (let ([test (make- 10)]) (seq-list (imethod-1 test) (imethod-2 test 20) (imethod-1 test) (imethod-3 test) (imethod-4 test 20) (imethod-3 test)))) `(20 ,(void) 40 160 ,(void) 320)) (eqv? (let () (import test-6) (let ([test (make- 10)]) (method-1 test))) 100) ;;; end of tests from Michael Lenaghan of frogware, Inc. ;;; letrec-classes tests from seminar (begin (define-syntax letrec-classes (syntax-rules () [(_ ([class-name (class-formal ...) (base-name base-arg ...) ([ivar ivar-init] ...) [method-name (method-formal ...) method-b1 method-b2 ...] ...] ...) b1 b2 ...) (let () (define-class (class-name class-formal ...) (base-name base-arg ...) (ivars [ivar ivar-init] ...) (methods [method-name (method-formal ...) method-b1 method-b2 ...] ...)) ... b1 b2 ...)])) #t) (error? ; wrong number of base-class arguments (letrec-classes ([ (x) () ()]) (letrec-classes ([ () () ()]) (make-)))) (error? ; no inherited foo method for (super) (letrec-classes ([ () () () [foo () (super)]]) (foo (make-)))) (eq? (let () (letrec-classes ([ (x) () ([x x]) [c1 (a) (make- a)] [c2 () x]]) (c2 (c1 (make- 44) 87)))) 87) (eq? (letrec-classes ((A () () ())) (letrec-classes (( () (A) () (foo () 77))) (foo (make-) 88))) 77) ; Ronald Garcia ; Here are some INVALID test cases that I use to exercise what errors my ; compiler will catch. A few might not fail given the proper compiler ; extension (i.e. do classes and variables share the same namespace...) (error? ; duplicate definition repeat, repeat?, and make-repeat (letrec-classes ([Repeat () () ()] [Repeat () () ()]) 0)) (error? ; duplicate ivar i (letrec-classes ([Vars () () ((i 1) (i 1))]) 0)) (error? ; unrecognized base class aaaaa (letrec-classes ([Empty () (aaaaa) ()]) (let ([mt (make-Empty)]) 0))) ;;; Chez Scheme allows this: (eqv? (letrec-classes ([One () () ()] [Two () (One) ()]) 0) 0) (error? ; unrecognized base class aaaaa (letrec-classes ([One () () ()]) (letrec-classes ([Two () (aaaaa) ()]) 0))) (error? ; duplicate same-arity method definition (letrec-classes ([Vars () () () (M1 () 0) (M1 () 1)]) 0)) (error? ; incorrect base argument count (letrec-classes ([Class () ( unbound) ()]) 0)) (error? ; unbound is not bound (letrec-classes ([c1 (x) () ()]) (letrec-classes ([c2 () (c1 unbound) ()]) (make-c2)))) (error? ; unbound is not bound (letrec-classes ([c () () ((i unbound))]) (make-c))) (error? ; j is unbound (letrec-classes ([c () () ((i j) (j 0))]) (make-c) 0)) (eqv? (letrec-classes ([c () () ((i 1) (j (+ i 2))) (m () j)]) (m (make-c))) 3) (error? ; unbound is not bound (letrec-classes ([c (i j) () ()]) (make-c 1 unbound))) (error? ; unbound is not bound (letrec-classes ([c (i j) () ()]) (c? unbound))) (error? ; unbound is not bound (letrec-classes ([Class () () () (M1 (i) unbound)]) (M1 (make-Class) 6))) (error? ; duplicate definition of M1 (letrec-classes ([One () () () (M1 () 0)] [Two () () () (M1 () 0)]) 0)) (eqv? (letrec-classes ([Pop () () () (M1 () 0)]) (letrec-classes ([One () (Pop) () (M1 () 1)] [Two () () () (M1 () 2)]) (M1 (make-Two)))) 2) (error? ; duplicate definition of M2 (letrec-classes ([Pop () () () (M1 () 0)]) (letrec-classes ([One () (Pop) () (M1 () 1) (M2 () 2)] [Two () (Pop) () (M2 () 2)]) 0))) (equal? (letrec-classes ([Pop () () () (M1 () 0)]) (letrec-classes ([One () (Pop) () (M1 () 1)] [Two () (Pop) () (M2 () 2)]) (let ([M2* M2]) (letrec-classes ([Three () (One) () (M1 () 3) (M2 () 4)]) (list (M1 (make-Pop)) (M1 (make-One)) (M1 (make-Two)) (M2* (make-Two)) (M1 (make-Three)) (M2 (make-Three))))))) '(0 1 0 2 3 4)) (error? ; variable ingnacious is unbound (letrec-classes ([Pop () () ([ingnacious 1])]) (letrec-classes ([One () () () (M1 () ingnacious)]) (M1 (make-One))))) (equal? (letrec-classes ([Pop () () ([i 1]) [get () i]]) (letrec-classes ([One () (Pop) ([i 2]) [get () (list (super) i)]]) (get (make-One)))) '(1 2)) (error? ; invalid syntax class (let ([Class #f]) (letrec-classes ([Class () () ()]) (let ([Class Class]) 0)))) (eqv? (letrec-classes ([Class () () ()]) (let ([Class #f] [foo (make-Class)]) (Class? foo))) #t) ; Here are some pretty trivial (i.e. relatively easy to follow by hand) test cases. ; They cover some pretty basic functionality (specifying classes without making them, etc.) (eq? ;; simplest example... (letrec-classes ([Empty () () ()]) 0) 0) (eq? ;; It's okay for ivars in separate classes to have the same name. (letrec-classes ([One () () ((var 0))] [Two () () ((var 0))]) 0) 0) (eq? ;; naive inheritance example (letrec-classes ([One () () ()]) (letrec-classes ([Two () (One) ()]) 0)) 0) (eq? ;; Actually make a class (letrec-classes ([Empty () () ()]) (let ([mt (make-Empty)]) 0)) 0) (eq? ;; simple example of using class formals in base-init (letrec-classes ([One (i) () ()]) (letrec-classes ([Two (j) (One j) ()]) 0)) 0) (eq? ;; simple example of using class formal in ivar-init. (letrec-classes ([Class (i) () ((var i))]) 0) 0) (eq? ;; ivar-init's can see the previous ivar. (letrec-classes ([Class () () ((var1 0) (var2 var1))]) 0) 0) (eq? ;; parameters to methods are visible in methods (letrec-classes ([Class () () () (M1 (i) i)]) 0) 0) (eq? ;; "self" is implicitly added to method environments. (letrec-classes ([Class () () () (M1 () self)]) 0) 0) (eq? ;; inheritance hierarchy can share methods (letrec-classes ([Pop () () () (M1 () 0)]) (letrec-classes ([One () (Pop) () (M1 () 1)] [Two () (Pop) () (M1 () 2)]) 0)) 0) (eq? ;; more windy inheritance hierarchy (letrec-classes ([Pop () () () (M1 () 0)]) (letrec-classes ([One () (Pop) () (M1 () 1)] [Two () (Pop) () (M2 () 2)]) (letrec-classes ([Three () (One) () (M1 () 1) (M3 () 2)] [Four () (Two) () (M2 () 1) (M4 () 2)]) 0))) 0) (eq? ;; Skip a generation before overloading... (letrec-classes ([Pop () () () (M1 () 0)]) (letrec-classes ([One () (Pop) ()]) (letrec-classes ([Three () (One) () (M1 () 1) (M3 () 2)]) 0))) 0) (eq? ;; classes in the same block can see each other. (letrec-classes ([One () () () (M1 () (make-Two))] [Two () () ()]) 0) 0) (eq? ;; classes in the same block can call each other's methods. (letrec-classes ([One () () () (M1 (obj) (M2 obj))] [Two () () () (M2 () 3)]) 0) 0) (eq? ;; class methods in the same block can be seen in base inits (letrec-classes ([Pop (i j) () ()]) (letrec-classes ([One () () () (M1 (obj) (M2 obj))] [Two () (Pop (M1 (make-One)) 5) () (M2 () 3)]) 0)) 0) (eq? ;; subclass methods can see superclass instance vars (letrec-classes ([Pop () () ([i 1])]) (letrec-classes ([One () (Pop) () (M1 () i)]) 0)) 0) (eq? ;; class names should become unique (letrec-classes ([Class () () ()]) (letrec-classes ([Class () () ()]) 0)) 0) (eq? ;; class names should not clash with variables either (let ([Class #f]) (letrec-classes ([Class () () ()]) (letrec-classes ([Class () () ()]) 0))) 0) (eq? ;; Variables bound outside letrec-classes should be visible (let ([bound-var #f]) (letrec-classes ([Super (i) () ()]) (letrec-classes ([Class () (Super bound-var) ([i bound-var]) (M1 () bound-var)]) 0))) 0) (eq? ;; Number has one instance variable that holds a number and one method ;; that returns the number. (letrec-classes ([Number (num^) () ((num num^)) (Val () num)]) (let ([nb1 (make-Number 1)] [nb2 (make-Number 2)]) (+ (Val nb1) (Val nb2)))) ;; result: 3 3) (eq? ;; test out method binding (letrec-classes ([Pop () () () (MP1 () 0) (MP2 (i) 0)]) (letrec-classes ([One () (Pop) () (M1 () 1)]) (letrec-classes ([Two () (One) () (M2 (i j) 2) (MP1 () 2)]) (letrec-classes ([Three () (Two) () (MP2 (i) 3) (M3 () 3)]) 0)))) 0) ; Mark Meiss (eq? (let ([object (letrec-classes ([duo (n) () ([n n]) (plus () (+ n 2)) (times () (* n 2)) (expt () (* n n)) (export () (let ([vec (make-vector 4)]) (vector-set! vec 0 self) (vector-set! vec 1 plus) (vector-set! vec 2 times) (vector-set! vec 3 expt) vec))]) (export (make-duo 6)))]) (* ((vector-ref object 1) (vector-ref object 0)) (+ ((vector-ref object 2) (vector-ref object 0)) ((vector-ref object 3) (vector-ref object 0))))) ; should evaluate to 384 384) ;------------------------------------------------------------------------ (eq? (letrec ([class-maker (lambda (n) (if (zero? n) (letrec-classes ([zero () () () (get-n () 0)]) (cons (make-zero) get-n)) (letrec-classes ([succ () () () (get-n () (let ([prev (class-maker (sub1 n))]) (add1 ((cdr prev) (car prev)))))]) (cons (make-succ) get-n))))] [fib (lambda (n) (if (< ((cdr n) (car n)) 2) ((cdr n) (car n)) (+ (fib (class-maker (sub1 ((cdr n) (car n))))) (fib (class-maker (sub1 (sub1 ((cdr n) (car n)))))))))]) (fib (class-maker 7))) ; should evaluate to 13 13) ;------------------------------------------------------------------------ (eq? (letrec-classes ([ (a b c) () ([a (+ a a)] [b (+ a b)] [c (+ b c)]) (get-b () b) (sum (a) (+ a (+ (get-b self) c)))]) (sum (make- 1 2 3) 4)) ; should evaluate to 15 15) ;------------------------------------------------------------------------ (equal? (letrec-classes ([A (x y) () ([x x] [y y]) (get-x () x) (get-y () y) (test (object) (if (A? object) (+ (- (get-x self) (get-x object)) (- (get-y self) (get-y object))) (* (get-x self) (get-y self))))]) (letrec-classes ([B () (A 2 3) () (become-if-not-A (object) (if (A? object) self object))] [C (x y) (A x y) (#; [x x] #; [y y])]) (let ([a-var (make-A 3 4)] [b-var (make-B)] [c-var (make-C 2 1)] [vec (make-vector 4)]) (vector-set! vec 0 (test a-var b-var)) (vector-set! vec 1 (test a-var c-var)) (set! b-var (become-if-not-A b-var b-var)) (vector-set! vec 2 (test a-var b-var)) (set! b-var (become-if-not-A b-var c-var)) (vector-set! vec 3 (test a-var b-var)) vec))) ; should evaluate to #(2 4 2 2) '#(2 4 2 2)) ;------------------------------------------------------------------------ #; (equal? (letrec-classes ([fish (head tail) () ([head head] [tail tail]) (behead () (set! head tail)) (betail () (set! tail head)) (get-head () head) (get-tail () tail)]) (letrec-classes ([guppy (head tail) (fish head tail) () (behead () (open-instance fish "" self) (set! head (cons tail tail))) (betail () (open-instance fish "" self) (set! tail (cons head head)))]) (letrec-classes ([minnow (head tail) (guppy head tail) () (behead () (begin (super) (set! betail behead))) (betail () (begin (super) (set! behead betail)))]) (let ([fishy-1 (make-fish 4 8)] [fishy-2 (make-guppy 5 9)]) (let ([fishy-red (make-minnow fishy-1 fishy-2)]) (behead fishy-1) (betail fishy-2) (behead fishy-red) (betail fishy-red) (get-tail (cdr (get-head fishy-red)))))))) ; should evaluate to (5 . 5) '(5 . 5)) ; Brooke Chenoweth (equal? ;; objects shouldn't be identifiable as vectors or procedures (letrec-classes ([foo () () ()]) (let ([obj (make-foo)]) (cons (foo? obj) (cons (procedure? obj) (cons (vector? obj) '()))))) ; should return '(#t #f #f) '(#t #f #f)) (eq? ;; We should be able to package up methods for outside use (let ([foo-package (letrec-classes ([foo (x) () ((x x)) (get-x () x)]) (let ([v (make-vector 3)]) (vector-set! v 0 (lambda (x) (make-foo x))) ; foo-maker (vector-set! v 1 (lambda (x) (foo? x))) ; foo? (vector-set! v 2 (lambda (inst) (get-x inst))) ; get-x v))]) (let ([make-foo (vector-ref foo-package 0)] [foo? (vector-ref foo-package 1)] [foo-get-x (vector-ref foo-package 2)]) (let ([r (letrec-classes ([R () () ()]) (make-R))] [f (make-foo 4)]) (if (foo? r) (foo-get-x r) (if (foo? f) (foo-get-x f) -100))))) ; should return 4 4) (equal? (letrec-classes ([A (x y) () ((s (+ x y)) (d (- x y))) (m1 () (- s d)) (m2 () (+ s d))] [R () () ()]) (letrec-classes ([B (x y z) (A y z) ((p (* x y))) (m1 () (+ (super) p)) (m3 () (- (m2 self) p))]) (let ([robj (make-R)] [aobj (make-A 1 2)] ; s = 3, d = -1 [bobj (make-B 3 4 5)] ; s = 9, d = -1, p = 12 [gather-results (lambda (obj) (and (A? obj) (cons (m1 obj) (cons (m2 obj) (cons (if (B? obj) (m3 obj) #f) '())))))] [v (make-vector 3)]) (vector-set! v 0 (gather-results robj)) (vector-set! v 1 (gather-results aobj)) (vector-set! v 2 (gather-results bobj)) v))) ; should return #( #f (4 2 #f) (22 8 -4)) '#(#f (4 2 #f) (22 8 -4))) ;; Allen Lee (equal? (letrec-classes ([superguy (x y) () ([x (* x x)] [y (let ([x 3]) (+ x (- y y)))] [z (lambda (x) (+ x x))]) (getX () x) (getY () y)]) (letrec-classes ([subguy (x y) (superguy (+ x x) (+ y y)) ([new-x x]) (plus (y) (+ new-x y))]) (letrec-classes ([subsubguy (x y z) (subguy (+ (+ x y) z) (getY (make-subguy x (* y z)))) () (minus (y) (- new-x y))]) (let ([supe (make-superguy 2 1)] [sub (make-subguy 3 4)] [subsub (make-subsubguy 1 2 3)]) (letrec ([map (lambda (p ls) (if (null? ls) '() (cons (p (car ls)) (map p (cdr ls)))))]) (let ([true (if (superguy? supe) (if (superguy? sub) (if (superguy? subsub) (if (subguy? sub) (if (subguy? subsub) (if (subsubguy? subsub) (if (not (subsubguy? sub)) (if (not (subsubguy? supe)) (not (subguy? supe)) #f) #f) #f) #f) #f) #f) #f) #f)] [x-es (map (lambda (obj) (getX obj)) (cons supe (cons sub (cons subsub '()))))] [y-es (map (lambda (obj) (getY obj)) (cons supe (cons sub (cons subsub '()))))]) (cons true (cons x-es y-es)))))))) '(#t (4 36 144) 3 3 3)) (equal? (letrec-classes ([NullEntity () () () (notifyme (evt) (if #f #f))]) (letrec-classes ([SchmentityEntity (int) (NullEntity) ([value int]) (notifyme (evt) (evt value))] [Pool (size) () ([numElements 0] [pool (make-vector size)] [observers (cons (make-NullEntity) '())]) (add (item) (begin (incrementElements self) (if (not (< (getCurrentIndex self) (vector-length pool))) ;; need to re-expand the pool (let ([newPool (make-vector (* (getSize self) (getLoadFactor self)))]) (letrec ([loop (lambda (n) (if (= n (getCurrentIndex self)) (begin (vector-set! newPool n item) newPool) (begin (vector-set! newPool n (vector-ref pool n)) (loop (add1 n)))))]) (setPool self (loop 0)))) (vector-set! pool (getCurrentIndex self) item)))) (remove (item) (letrec ([loop (lambda (n) (if (not (= n (getNumElements self))) (if (= (vector-ref pool n) item) (letrec ([shift (lambda (start) (if (= start (getCurrentIndex self)) (vector-set! pool start (void)) (begin (vector-set! pool start (vector-ref pool (+ start 1))) (shift (+ n 1)))))]) (shift n)) (decrementElements self)) (loop (+ n 1))))]) (loop 0))) (isEmpty () (= (getNumElements self) 0)) (getCurrentIndex () (- (getNumElements self) 1)) (getSize () (vector-length pool)) (getNumElements () numElements) (incrementElements () (set! numElements (+ numElements 1))) (decrementElements () (if (not (= (getNumElements self) 0)) (set! numElements (- numElements 1)))) (getPool () pool) (setPool (newPool) (set! pool newPool)) (notify (evt) (letrec ([loop (lambda (ls) (if (null? ls) '() (cons (notifyme (car ls) evt) (loop (cdr ls)))))]) (loop observers))) (subscribe (obj) (set! observers (cons obj observers))) (purgeObservers () (set! observers (cons (make-NullEntity) '()))) (getLoadFactor () 2) (contains (item) (letrec ([loop (lambda (n) (if (< n (getNumElements self)) (if (= item (vector-ref pool n)) #t (loop (+ n 1))) #f))]) (loop 0)))]) (let ([pool (make-Pool 37)]) (letrec ([addToPool (lambda (n) (if (= n 0) (isEmpty pool) (begin (add pool n) (addToPool (sub1 n)))))]) (addToPool 42) (addToPool 23) (remove pool 14) (subscribe pool (make-SchmentityEntity 23)) (subscribe pool (make-SchmentityEntity 14)) (let ([notified (notify pool (lambda (x) (* x 3)))]) (cons (isEmpty pool) (cons (getCurrentIndex pool) (cons (getPool pool) (cons (getNumElements pool) (cons (contains pool 23) (cons (contains pool 15) notified))))))))))) ; should evaluate to (#f 63 #74(some-huge-vector-with-65-elements) 64 #t #t 42 69 #) `(#f 63 #74(42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0) 64 #t #t 42 69 ,(void))) (equal? (letrec-classes ([broken () () ([vec (make-vector 5)]) (object-or-vector (n) (if (< n 7) (begin (vector-set! vec 0 14) (vector-set! vec 1 15) (vector-set! vec 2 16) vec) self))]) (letrec-classes ([fixed-broken (num) (broken) () (object-or-vector (n) (* n n))]) (let ([all-k (make-broken)]) (let ([still-valid1 (if (vector? (object-or-vector all-k 4)) (vector-ref (object-or-vector all-k 4) 0) #f)] [still-valid2 (if (vector? (object-or-vector all-k 5)) (vector-ref (object-or-vector all-k 5) 1) #f)] [still-valid3 (if (vector? (object-or-vector all-k 6)) (vector-ref (object-or-vector all-k 6) 2) #f)] [is-vector? (vector? (object-or-vector all-k 7))] [fixed (make-fixed-broken 37)]) (cons (object-or-vector fixed 37) (cons still-valid1 (cons still-valid2 (cons still-valid3 (cons is-vector? '()))))))))) ;; should return the list (14 15 16 #t) '(1369 14 15 16 #f)) ;; Matthew Garrett ;;; eopl-tests.ss ;;; These test cases are translated as directly as possible from "Essentials ;;; of Programming Languages", 2nd Ed. by Friedman, Wand, and Haynes, Chapter ;;; 5, Objects and Classes. (equal? ;;; Figure 5.1, A simple object-oriented program (letrec-classes ([c1 (x) () ([i x] [j (- 0 x)]) (countup (d) (set! i (+ i d)) (set! j (- j d))) (getstate () (list i j))]) (let ([t1 0] [t2 0] [o1 (make-c1 3)]) (set! t1 (getstate o1)) (countup o1 2) (set! t2 (getstate o1)) (list t1 t2))) '((3 -3) (5 -5))) (eq? ;;; page 172, odd-even (letrec-classes ([oddeven () () () (even (n) (if (zero? n) 1 (odd self (sub1 n)))) (odd (n) (if (zero? n) 0 (even self (sub1 n))))]) (let ([o1 (make-oddeven)]) (odd o1 13))) 1) (eq? ;;; Figure 5.2 Object-oriented program for summing the leaves of a tree (letrec-classes ([ () () () [sum () (void)]]) (letrec-classes ([interior_node (l r) () ([left l] [right r]) (sum () (+ (sum left) (sum right)))] [leaf_node (v) () ([value v]) (sum () value)]) (let ([o1 (make-interior_node (make-interior_node (make-leaf_node 3) (make-leaf_node 4)) (make-leaf_node 5))]) (sum o1)))) 12) (equal? ;;; Figure 5.3 Classic example of inheritance: colorpoint (letrec-classes ([point (initx inity) () ([x initx] [y inity]) (move (dx dy) (set! x (+ x dx)) (set! y (+ y dy))) (get_location () (list x y))] [colorpoint (initx inity) (point initx inity) ([color 0]) (set_color (c) (set! color c)) (get_color () color)]) (let ([p (make-point 3 4)] [cp (make-colorpoint 10 20)]) (move p 3 4) (set_color cp 87) (move cp 10 20) (list (get_location p) (get_location cp) (get_color cp)))) ;;; should return '((6 8) (20 40) 87) '((6 8) (20 40) 87)) #; (equal? ;;; page 175, shadowing (letrec-classes ([c1 () () ([x 0] [y 0]) (setx1 (v) (set! x v)) (sety1 (v) (set! y v)) (getx1 () x) (gety1 () y)]) (letrec-classes ([c2 () (c1) ([y2 0]) (sety2 (v) (set! y2 v)) (getx2 () (open-instance c1 "" self) x) (gety2 () y2)]) (let ([o2 (make-c2)]) (setx1 o2 101) (sety1 o2 102) (sety2 o2 999) (list (getx1 o2) (gety1 o2) (getx2 o2) (gety2 o2))))) ;;; should return '(101 102 101 999) '(101 102 101 999)) (equal? ;;; page 176, redefining methods (letrec-classes ([c1 () () () (m1 () 1) (m2 () (m1 self))] [c2 () (c1) () (m1 () 2)]) (let ([o1 (make-c1)] [o2 (make-c2)]) (list (m1 o1) (m1 o2) (m2 o2)))) '(1 2 2)) (equal? ;;; Figure 5.4 Example illustrating interaction of self and inheritance (letrec-classes ([c1 () () () (m1 () 1) (m2 () 100) (m3 () (m2 self))] [c2 () (c1) () (m2 () 2)]) (let ([o1 (make-c1)] [o2 (make-c2)]) (list (m1 o1) ; 1 (m2 o1) ; 100 (m3 o1) ; 100 (m1 o2) ; 1 (from c1) (m2 o2) ; 2 (from c2) (m3 o2)))) ; 2 (c1's m3 calls c2's m2) '(1 100 100 1 2 2)) (eq? ;;; Figure 5.5 Example demonstrating a need for static method dispatch (letrec-classes ([point (initx inity) () ([x initx] [y initx]) (move (dx dy) (set! x (+ x dx)) (set! y (+ y dy))) (getlocation () (list x y))] [colorpoint (initx inity initcolor) (point 0 0) ([color initcolor]) (set_color (c) (set! color c)) (get_color () color)]) (let ([o1 (make-colorpoint 3 4 172)]) (get_color o1))) 172) (eq? ;;; Figure 5.6 Example illustrating interaction of super call with self (letrec-classes ([c1 () () () (m1 () (m2 self)) (m2 () 13)]) (letrec-classes ([c2 () (c1) () (m1 () (super)) (m2 () 23) (m3 () (m1 self))]) (letrec-classes ([c3 () (c2) () (m1 () (super)) (m2 () 33)]) (let ([o3 (make-c3)]) (m3 o3))))) 33) ; Jeremiah Willcock (eq? (let () (define-class (A n) () (ivars [next (foo n)]) (methods [get-next () next] [get-length () (if (null? next) 0 (+ 1 (get-length (get-next self))))])) (define (foo n) (if (zero? n) '() (make-A (- n 1)))) (let ((a (make-A 10))) (get-length a))) 10) (eq? (letrec-classes ((A (n) () ((next (if (zero? n) '() (make-A (- n 1))))) (get-next () next) (get-length () (if (null? next) 0 (+ 1 (get-length (get-next self))))))) (let ((a (make-A 10))) (get-length a))) 10) ; should this really be an error? It's not clear how to make base ivars ; visible in ivar inits efficiently if we want to do so. (error? ; variable oop-x1 is not bound (let () (define-class ( oop-x) () (ivars [oop-x1 oop-x])) (define-class ( oop-x) ( oop-x) (ivars [oop-x2 (+ oop-x1 oop-x1)])) (define-class ( oop-x) ( oop-x) (ivars [oop-x3 (+ oop-x2 oop-x2)])) (define-class ( oop-x) ( oop-x) (ivars [oop-x4 (+ oop-x3 oop-x3)])) (define-class ( oop-x) ( oop-x) (ivars [oop-x5 (+ oop-x4 oop-x4)])) (define-class ( oop-x) ( oop-x) (ivars [oop-x6 (+ oop-x5 oop-x5)])) (define-class ( oop-x) ( oop-x) (ivars [oop-x7 (+ oop-x6 oop-x6)])) (define-class ( oop-x) ( oop-x) (ivars [oop-x8 (+ oop-x7 oop-x7)])) (define-class ( oop-x) ( oop-x) (ivars [oop-x9 (+ oop-x8 oop-x8)]) (methods [m () oop-x9])) (m (make- 1)))) (eq? (let () (define-class ( x0) () (ivars [x1 (+ x0 x0)] [x2 (+ x1 x1)] [x3 (+ x2 x2)] [x4 (+ x3 x3)] [x5 (+ x4 x4)] [x6 (+ x5 x5)] [x7 (+ x6 x6)] [x8 (+ x7 x7)] [x9 (+ x8 x8)]) (methods [m () x9])) (m (make- 1))) 512) ; Abdulaziz Ghuloum (begin (define-class (R) ()) #t) (eq? (R? 0) #f) (eq? (R? (cons 1 2)) #f) (eq? (R? (make-vector 2)) #f) (eq? (R? (lambda () 4)) #f) (eq? (R? #f) #f) (eq? (R? #t) #f) (eq? (R? '()) #f) (equal? (letrec-classes ([AA () () ([x 0][y 0]) (get-x () x) (get-y () y) (set-x (a) (letrec-classes ([AA () () () (set-x (a) (set! x a))]) (set-x (make-AA) a))) (set-y (a) (letrec-classes ([AA () () ([y 0]) (set-y (a) (set! y a))]) (set-y (make-AA) a)))]) (let ([a (make-AA)]) (set-x a 5) (set-y a 0) (cons (get-x a) (get-y a)))) '(5 . 0)) (eq? (letrec-classes ([ (a b) () ([a a][b b]) (car () a) (cdr () b) (set-car! (x) (set! a x)) (set-cdr! (x) (set! b x))]) (let ([cons (lambda (a b) (make- a b))] [pair? (lambda (x) (? x))]) (let ([x (cons 4 5)]) (let ([y (cons 3 4)]) (set-car! y 12) (set-cdr! x y) (let ([cdr (cdr x)]) (if (pair? cdr) (let ([car (car cdr)]) (if (pair? car) #f car)))))))) 12) ; this doesn't test the oop system at all: #; (equal? (let ([letrec-classes (lambda (x y) (cons x y))] [ (lambda () 7)] [y (lambda () 3)] [x (lambda (y) y)] [self (cons 12 (cons 34 45))] [A (lambda (a b c d) (lambda () (let ([v (make-vector 4)]) (vector-set! v 0 a) (vector-set! v 1 b) (vector-set! v 2 c) (vector-set! v 3 d) v)))] [make (lambda (a b) b)] [inc-x (lambda (a b) (cons a b))] [s (lambda () 87)]) (letrec-classes ([A (y) () ([x y]) (inc-x (s) (begin self))]) (inc-x (make-A 3) 3))) '(#4(3 7 3 (87 12 34 . 45)) 3 . 3)) (eq? (let ([let 0][lambda 1][letrec 2][if 5]) (letrec-classes ([A (x) () ([x x]) (inc-x (s) (begin (set! x (+ x s)) self)) (get-x () x)]) (get-x (inc-x (make-A 4) 3)))) 7) ; Jeremiah Willcock (eq? (letrec-classes () #f) #f) (eq? (letrec-classes ((A () () ())) (letrec-classes ((B () (A) ())) (make-B) #f)) #f) (eq? (letrec-classes ((A () () () (foo () 5))) (letrec-classes ((B () (A) () (foo () 7) (bar () 8))) (foo (make-B)))) 7) (equal? (letrec-classes ((A (x y) () ((x x) (y y)) (get-x () x) (get-y () y) (set-x (value) (set! x value)))) (let ((A (make-A 1 2))) (cons (get-x A) (get-y A)))) '(1 . 2)) (eq? (letrec-classes ((A () () ())) (letrec-classes (( () (A) () (foo () 5))) (foo (make-)))) 5) #; (equal? (letrec-classes ((A (x y) () ((x (* 2 x)) (y (+ 7 y))) (get-x () (- x 3)) (get-y () (* 2 y)))) (letrec-classes (( (z w) (A (* w z) (- w z)) () (get-x () (open-instance A "" self) x) (set-x! () (open-instance A "" self) (set! x )) (call-get-x (set-x!) (get-x set-x!)) (call-set-x! (A) (set-x! self A)))) (let (( (make- 4 9))) (let ((x (get-x )) (y (get-y )) (x2 (call-get-x ))) (cons x (cons y (cons x2 (let ((foo (set-x! 7))) (cons (get-x ) '()))))))))) '(72 24 72 7)) #; (equal? (letrec-classes ((A (x y) () ((x (* 2 x)) (y (+ 7 y))) (get-x () (- x 3)) (get-y () (* 2 y)))) (letrec-classes (( (z w) (A (* w z) (- w z)) () (get-x () (open-instance A "" self) x) (set-x! () (open-instance A "" self) (set! x )) (call-get-x (set-x!) (get-x set-x!)) (call-set-x! (A) (set-x! self A)))) (let (( (make- 4 9))) (let ((x (get-x )) (y (get-y )) (x2 (call-get-x ))) (cons x (cons y (cons x2 (let ((foo (set-x! 7))) (cons (get-x ) '()))))))))) '(72 24 72 7)) #; (equal? (letrec-classes ((A (x y) () ((x (* 2 x)) (y (+ 7 y))) (get-x () (- x 3)) (get-y () (* 2 y)))) (letrec-classes (( (z w) (A (* w z) (- w z)) () (get-x () (open-instance A "" self) x) (set-x! () (open-instance A "" self) (set! x )) (call-get-x (set-x!) (get-x set-x!)) (call-set-x! (A) (set-x! self A)))) (let (( (make- 4 9))) (let ((x (get-x )) (y (get-y )) (x2 (call-get-x ))) (cons x (cons y (cons x2 (let ((foo (set-x! 7))) (cons (get-x ) '()))))))))) '(72 24 72 7)) (eq? (letrec-classes ((A (x y) () ((x (* 2 x)) (y (+ 7 y))) (get-x () x))) (letrec-classes (( (z w) (A (* w z) (- w z)) () (get-x () 7) (call-get-x (set-x!) (get-x set-x!)))) (let (( (make- 4 9))) (call-get-x )))) 7) (eq? (letrec-classes ((A () () ())) (letrec-classes (( () (A) () (set-x! () #f))) #f)) #f) #; (equal? (letrec-classes ((A (x y) () ((x (* 2 x)) (y (+ 7 y))) (get-x () (- x 3)) (get-y () (* 2 y)))) (letrec-classes (( (z w) (A (* w z) (- w z)) () (get-x () (open-instance A "" self) x) (set-x! () (open-instance A "" self) (set! x )) (call-get-x (set-x!) (get-x set-x!)) (call-set-x! (A) (set-x! self A)))) (let (( (make- 4 9))) (let ((x (get-x )) (y (get-y )) (x2 (call-get-x ))) (cons x (cons y (cons x2 (let ((foo (set-x! 7))) (cons (get-x ) '()))))))))) '(72 24 72 7)) (equal? (letrec-classes ((xself () () ((x 7)) (xisa-vtable? () (let ((self 5)) (+ x self))))) (cons (xisa-vtable? (make-xself)) (xself? (make-xself)))) '(12 . #t)) (equal? (letrec-classes ((xself () () ((x 7)) (isa-vtable? () (let ((self 5)) (+ x self))))) (cons (isa-vtable? (make-xself)) (xself? (make-xself)))) '(12 . #t)) (equal? (letrec-classes ; Cannot have class named "self" ((self () () ((x 7)) (isa-vtable? () (let ((self 5)) (+ x self))))) (cons (isa-vtable? (make-self)) (self? (make-self)))) '(12 . #t)) (eq? (let ((self 5)) (letrec-classes ((A () () () (foo () self) (bar () 5))) (let ((self 7)) (bar (foo (make-A)))))) 5) (equal? (letrec-classes ((A () () ()) (B () () ())) (letrec-classes ((C () (A) ())) (letrec-classes ((D () (C) ())) (let ((isa-grid-entry (lambda (obj) (cons (A? obj) (cons (B? obj) (cons (C? obj) (cons (D? obj) '()))))))) (letrec ((map (lambda (f l) (if (null? l) '() (cons (f (car l)) (map f (cdr l))))))) (map isa-grid-entry (cons 5 (cons (make-A) (cons (make-B) (cons (make-C) (cons (make-D) '()))))))))))) '((#f #f #f #f) (#t #f #f #f) (#f #t #f #f) (#t #f #t #f) (#t #f #t #t))) (equal? (letrec-classes ((A () () ())) (let ((z (make-A))) (cons (pair? z) (cons (vector? z) (cons (null? z) (cons (procedure? z) (cons (boolean? z) '()))))))) '(#f #f #f #f #f)) #; (equal? (let ((x 7)) (letrec-classes ((A () () ((y x)))) (letrec-classes ((B () (A) () (set-x (value) (set! x value)) (get-y () (open-instance A "" self) y))) (let ((w (make-B))) (set-x w 9) (cons (get-y w) x))))) '(7 . 9)) (equal? (letrec-classes ((A () () () (x () 1) (y () 2))) (letrec-classes ((B () (A) () (x () (- 0 (super))) (z () 3))) (letrec-classes ((C () (B) () (y () (+ 10 (super))) (z () (- 0 (super))))) (let ((a (make-A)) (b (make-B)) (c (make-C))) (cons (cons (x a) (y a)) (cons (cons (x b) (cons (y b) (z b))) (cons (cons (x c) (cons (y c) (z c))) '()))))))) '((1 . 2) (-1 2 . 3) (-1 12 . -3))) (eq? ; Based on suggestion in class about constructors making the same class (letrec-classes ((A (n) () ((next (if (zero? n) '() (make-A (- n 1))))) (get-next () next) (get-length () (if (null? next) 0 (+ 1 (get-length (get-next self))))))) (let ((a (make-A 10))) (get-length a))) 10) (equal? ; Automatic differentiator -- expressions of one variable w/ int constants (letrec-classes ((Differentiable () () () (compute () #f) (diff () #f))) (letrec-classes ( (sum (a b) (Differentiable) ((a a) (b b)) (compute () (lambda (x) (+ ((compute a) x) ((compute b) x)))) (diff () (make-sum (diff a) (diff b)))) (prod (a b) (Differentiable) ((a a) (b b)) (compute () (lambda (x) (* ((compute a) x) ((compute b) x)))) (diff () (make-sum (make-prod a (diff b)) (make-prod b (diff a))))) (pow (a b) (Differentiable) ((a a) (b b)) ; Constant exponent (compute () (letrec ((real-pow (lambda (base power) (if (zero? power) 1 (* base (real-pow base (- power 1))))))) (lambda (x) (real-pow ((compute a) x) b)))) (diff () (if (zero? b) (make-constant 0) (make-prod (make-constant b) (make-prod (make-pow a (- b 1)) (diff a)))))) (constant (x) (Differentiable) ((x x)) (compute () (lambda (z) x)) (diff () (make-constant 0))) (variable () (Differentiable) () (compute () (lambda (x) x)) (diff () (make-constant 1)))) (let ((+ (lambda (a b) (make-sum a b))) (- (lambda (a b) (make-sum a (make-prod b (make-constant -1))))) (* (lambda (a b) (make-prod a b))) (^ (lambda (a b) (make-pow a b))) (! (lambda (x) (make-constant x))) (x (make-variable))) (let ((fun (+ (^ (- x (! 1)) 9) (* x (! 7))))) (letrec ((diff-at-values (lambda (fun ndiffs vals) (if (zero? ndiffs) '() (cons (letrec ((map (lambda (f l) (if (null? l) '() (cons (f (car l)) (map f (cdr l))))))) (map (compute fun) vals)) (diff-at-values (diff fun) (sub1 ndiffs) vals)))))) (diff-at-values fun 4 '(-5 -4 -3 -2 -1 0 1 2 3 4 5))))))) '((-10077731 -1953153 -262165 -19697 -519 -1 7 15 533 19711 262179) (15116551 3515632 589831 59056 2311 16 7 16 2311 59056 589831) (-20155392 -5625000 -1179648 -157464 -9216 -72 0 72 9216 157464 1179648) (23514624 7875000 2064384 367416 32256 504 0 504 32256 367416 2064384))) ; Robert George (eq? (letrec-classes ([A () () ([x 1] [y (letrec-classes ([B () () ([x2 2]) (get-x () (if x2 x2 (letrec-classes ([C () () ([x3 3]) (get-x () x3)]) (let ([obj (make-C)]) (get-x obj)))))]) (let ([obj (make-B)]) (get-x obj)))]) (get-x () x)]) (get-x (make-A))) 1) (equal? (letrec ([map (lambda (proc ls) (if (null? ls) '() (cons (proc (car ls)) (map proc (cdr ls)))))]) (letrec-classes ([A () () ([x 0]) (square-and-set (y) (let ([val (* y y)]) (set! x (+ x val)) val)) (get-x () x)]) (let ([obj (make-A)]) (let ([ls (map (lambda (x) (square-and-set obj x)) '(1 2 3 4 5))]) (cons ls (get-x obj)))))) '((1 4 9 16 25) . 55)) #; (eq? (let ([x 5]) (letrec-classes ([A () () ([x 3]) (get-x () x)]) (letrec-classes ([B () (A) ([y 4]) (get-x () (open-instance A "" self) x)]) (+ x (get-x (make-B)) (get-x (make-A)))))) 11) (eq? (letrec-classes ([A () () ([x 1] [y (+ x x)]) (get-x () x) (get-y () y)]) (letrec-classes ([B () (A) ([z 3]) (add-em () (+ (get-x (make-A)) (get-x (make-B)) z))]) (add-em (make-B)))) 5) (eq? (letrec-classes ([A () () ([x 1]) (get-x () x)]) (letrec-classes ([B () (A) ([y 3]) (get-x () (super))]) (get-x (make-B)))) 1) (eq? (letrec-classes ([A () () ([x 1]) (create-A () (make-A))]) (letrec-classes ([B () (A) ([y 2]) (do-it () (A? (create-A (make-B))))]) (do-it (make-B)))) #t) (eq? (let () (define-syntax albatross (syntax-rules () [(_ f m) (begin (define-class (fowl) () (ivars [x 77]) (methods [m () x])) (define f (lambda () (make-fowl))))])) (albatross alcatraz pelican) (pelican (alcatraz))) 77) (error? ; variable make-fowl is not bound (make-fowl)) ; Jeremy Siek (eq? (letrec-classes ((shape () () () (foo (s) s))) (letrec-classes ((rect () (shape) () (get-h () 0) (foo (s) s))) (let ([r (make-rect)]) (get-h r)))) 0) )