[4/26/99] =============================================================================== * Last time we saw how closures are used as objects that store information. The same principle be used to create "objects" in a simple way - here is a complete example for a defstruct-like construct: -------------------- (define (make-point x y) (lambda (msg) (case msg ((get-x) x) ((get-y) y) (else (error "point: unknown message."))))) (define (get-x p) (p 'get-x)) (define (get-y p) (p 'get-y)) -------------------- We can even extend this definition to allow modifying internal elements: -------------------- (define (make-point x y) (lambda (msg) (case msg ((get-x) x) ((get-y) y) ((set-x!) (lambda (v) (set! x v))) ((set-y!) (lambda (v) (set! y v))) (else (error "point: unknown message."))))) (define (get-x p) (p 'get-x)) (define (get-y p) (p 'get-y)) (define (set-x! p v) ((p 'set-x!) v)) (define (set-y! p v) ((p 'set-y!) v)) -------------------- You could also define a "sub-structure" and use the environment diagram to see how exactly this is done: -------------------- (define (make-point3d x y z) (let ((p (make-point x y))) (lambda (msg) (case msg ((get-z) z) ((set-z!) (lambda (v) (set! z v))) (else (p msg)))))) ; this delegates to the intenal object (define (get-z p) (p 'get-z)) (define (set-z! p v) ((p 'set-z!) v)) -------------------- One thing to note is that the object exports only variables that it wants to, so you could implement security mechanism that will allow modifications only in a consistent way (similar to C++'s private members with accessor functions). For example, see this: -------------------- (define (make-point x y) (lambda (msg) (let ((sum (+ x y))) (define (fix-sum) (set! sum (+ x y))) (case msg ((sum) sum) ((get-x) x) ((get-y) y) ((set-x!) (lambda (v) (set! x v) (fix-sum))) ((set-y!) (lambda (v) (set! y v) (fix-sum))) (else (error "point: unknown message.")))))) -------------------- =============================================================================== * It is also possible to have functions with local "static" variables - static variables in C are ones that are local to a function but they retain their value from one call to another. Here is a Scheme example: -------------------- (define count (let ((counter 0)) (lambda () (set! counter (inc counter)) counter))) -------------------- Note that the value of the counter variable is visible _only_ inside the count function, and no one except for this function can touch it. =============================================================================== * That can be combined with functional structures to create values that are local to a "class", but static: -------------------- (define make-point (let ((counter 0)) (lambda (x y) (set! counter (inc counter)) (lambda (msg) (case msg ((get-x) x) ((get-y) y) ((set-x!) (lambda (v) (set! x v))) ((set-y!) (lambda (v) (set! y v))) ((get-counter) counter) (else (error "point: unknown message."))))))) -------------------- Note that this didn't "export" any way to modify counter, so it cannot be changed from the outside. ===============================================================================