#lang racket (provide error-obj make-obj) (define error-obj (lambda (msg . args) (error 'dispatch "no field ~a" msg))) (define make-obj (lambda maybe-parent (let ([delegate (get-arg-or-default maybe-parent error-obj)]) (let ([table (make-hash)]) (lambda msg (match msg [(list (? symbol? x)) ;; a list with one symbol (hash-ref table x ;; ;; it's a get (lambda () (delegate x)))] ;; look up x in the delegate [(list (? symbol? x) v) ;; it's a set (hash-set! table x v)] [else (error 'make-obj "invalid object lookup syntax ~a" msg)])))))) (define get-arg-or-default (lambda (args default) (if (null? args) default (car args)))) ;;; demonstrating inheritance ;;; ------------------------- (define b (make-obj)) ;; base object (b 'x 5) ;; install the binding (x 5) in b (define c (make-obj b)) ;; c inherits from b (require rackunit) ;; install the binding (y 7) in c (c 'y 7) ;; return y's binding => 7 (check-eq? (c 'y) 7 "c7") ;; return x's binding => 5 (check-eq? (c 'x) 5 "c5") ;; create the binding (x 3) in c (c 'x 3) ;; => 3 (check-eq? (c 'x) 3 "c3") ;; => 5 b's binding for x remains unchanged (check-eq? (b 'x) 5 "b5")