CSC151 2007S, Class 50: An Object Example Admin: * Are there questions on exam 3? * I've added my counts for the higher-order solutions. Overview: * Review of reading. * An extended example. /Last Class/ * We like to represent compound values * Many techniques: lists, vectors, files, association lists, trees (?) * But we want to put a barrier between the client that uses the compound value and our underlying implementation * So that changes to the implemetnation/structure don't break the other code. /Review of Reading/ * A solution: Make objects. Objects are things that have a lambda inside of a let (define thor (let ((...)) (lambda (message . params) ...))) * The things defined in the let are only available to the lambda, so we have some barriers in place * Interact with with objects by sending them "messages" that tell them what to do. * Question: How does the let prevent someone from accessing the underlying representation? * The variables are locally bound. * Ignore objects, return just to let (let ((name0 exp0) (name1 exp1) ... (namen expn)) stuff) * The names given in the let can only be used within stuff * It feels like one the let is done, the variables are gone. * So how does the procedure defined with the lambda still use them? * Variables named by a let don't disappear until there is no code that references them. * Why not do (lambda (message . params) (let ((...)) ...)) * This still provides the barrier ... external things cannot access the things named in the let * However, in the (let ((...)) (lambda ...)) the named things are *fixed* - they are shared between different function calls * In the (lambda (let ..) ...), we create a new set of names each time (define sams-grades (let ((total (vector 0)) (count (vector 0))) (lambda (message . params) (cond ((eq? message ':add!) (let ((newgrade (car params))) (vector-set! total 0 (+ newgrade (vector-ref total 0) )) (vector-set! count 0 (+ 1 (vector-ref count 0))))) ((eq? message ':average) (/ (vector-ref total 0) (vector-ref count 0))) (else (error 'sams-grades' "Unknown message" message)))))) REVISED (define sams-grades (let ((total (vector 0)) (count (vector 0))) (lambda (message . params) (cond ((eq? message ':add!) (let ((newgrade (car params))) (vector-set! total 0 (+ newgrade (vector-ref total 0) )) (vector-set! count 0 (+ 1 (vector-ref count 0))))) ((eq? message ':average) (if (not (null? params)) (error "Only bozos provide parameters to average!")) (/ (vector-ref total 0) (vector-ref count 0))) ((eq? message ':save-to-file) (let* ((filename (car params)) (port (open-output-file filename))) (write (encrypt (vector-ref total 0)) port) (newline port) (write (encrypt (vector-ref count 0)) port) (newline port) (close-output-port port))) ((eq? message ':load-from-file!) (let* ((filename (car params)) (port (open-input-file filename)) (saved-total (decrypt (read port))) (saved-count (decrypt (read port)))) (close-input-port port) (vector-set! total 0 saved-total) (vector-set! count 0 saved-count))) (else (error 'sams-grades "Unknown Message")))))) (define encrypt (lambda (val) (list "I bet you can't figure out what the next value is " val))) (define decrypt cadr) We need procedures that build objects, not just procedures that represent objects (define make-grades (lambda () (let ((total (vector 0)) (count (vector 0))) (lambda (message . params) (cond ((eq? message ':add!) (let ((newgrade (car params))) (vector-set! total 0 (+ newgrade (vector-ref total 0) )) (vector-set! count 0 (+ 1 (vector-ref count 0))))) ((eq? message ':average) (if (not (null? params)) (error "Only bozos provide parameters to average!")) (/ (vector-ref total 0) (vector-ref count 0))) ((eq? message ':save-to-file) (let* ((filename (car params)) (port (open-output-file filename))) (write (encrypt (vector-ref total 0)) port) (newline port) (write (encrypt (vector-ref count 0)) port) (newline port) (close-output-port port))) ((eq? message ':load-from-file!) (let* ((filename (car params)) (port (open-input-file filename)) (saved-total (decrypt (read port))) (saved-count (decrypt (read port)))) (close-input-port port) (vector-set! total 0 saved-total) (vector-set! count 0 saved-count))) (else (error 'sams-grades "Unknown Message")))))))