MIT 6.001 Fall, 1997 Instructor: A. Meyer Recitation #7, Notes for Wed., 11/12/97 IN-CLASS EXERCISE: Implement two objects, YOU and ME, as message-passing procedures. Each of these objects has three methods, each taking no arguments: a NAME method which returns the object's name ('you or 'me), a YOU method which returns the object YOU, and a ME method which returns the object ME. SOLUTION: A very simple solution was proposed by one student in the section: (define (me mes) (cond ((eq? 'name mes) (lambda () 'me)) ((eq? 'me mes) (lambda () me)) ((eq? 'you mes) (lambda () you)) (else (fail)))) (define (you mes) (cond ((eq? 'name mes) (lambda () 'you)) ((eq? 'me mes) (lambda () me)) ((eq? 'you mes) (lambda () you)) (else (fail)))) This is neat and works pretty well, but has one serious problem. Suppose we save the ME object in another variable: (define me-object me) and then (define me 1) Then ME-OBJECT stops working properly! The problem is that the ME and YOU variable occurrences inside the object methods refer to the global variables ME and YOU which are vulnerable to re-use, whereas they should refer to LOCAL SLOTS which hold the ME and YOU objects. That is, we want (define me (let ((name 'me) (me 'will-be-me) (you 'will-be-you)) (lambda (mes) (cond ((eq? 'name mes) (lambda () name)) ((eq? 'me mes) (lambda () me)) ((eq? 'you mes) (lambda () you)) (else (fail)))))) and similarly for YOU: (define you (let ((name 'you) (me 'will-be-me) (you 'will-be-you)) (lambda (mes) (cond ((eq? 'name mes) (lambda () name)) ((eq? 'me mes) (lambda () me)) ((eq? 'you mes) (lambda () you)) (else (fail)))))) Then we want to SET! the local ME and YOU variables in both objects to the values of the global ME and YOU variables, after which it is safe to clobber the global variables. Now we have a new problem: the local variables are local! They are not accessible to be SET!'ed by a top-level expression evaluation. A fix that was suggested is to add some "system" methods to the objects which return the needed ABILITY TO SET! THE LOCAL VARIABLES: (define me (let ((name 'me) (me 'will-be-me) (you 'will-be-you)) (lambda (mes) (cond ((eq? 'name mes) (lambda () name)) ((eq? 'me mes) (lambda () me)) ((eq? 'you mes) (lambda () you)) ((eq? 'set-me! mes) (lambda (new-me) (set! me new-me))) ((eq? 'set-you! mes) (lambda (new-you) (set! you new-you))) (else (fail)))))) and likewise for the YOU object. So now both ME and YOU are corrrectly defined except that their ME and YOU slots are uninitialized. To initialize them, just: (ask me 'set-you! you) ;same as ((me 'set-you!) you) (ask me 'set-me! me) (ask you 'set-you! you) (ask you 'set-me! me) and everything is wired-up as desired. This solution works quite well, but has the regrettable feature that the ME and YOU objects are permanently stuck with system methods SET-ME! and SET-YOU! which are only needed in constructing the objects and not thereafter. REMOVING THIS REGRETTABLE FEATURE IS THE TOPIC OF THE NEXT 5 MINUTE PRESENTATION.