6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology 6.001 Notes: Section 14. 4 Slide 14.4.1 Cleaning up some details of our implementation So we have seen a first pass at building an object-oriented tem, using Scheme as the base. There are a few details that The need for self-reference we still need to clean up however. These include what to do if a.Dealing withtags'" class does not have a method to handle some request, the need to be able to refer to the object within methods belong to an object (i.e. an ability to recursively use methods of an object within an object), and the need to identify types of objects Detection of methods (or missing methods) Slide 14. 4.2 Use (no-method) to indicate that there is no method What happens if the object doesnt know how to handle a ( define n。- method message? We need a way to detect if we actually have a method (lot ((tag (list No-METHOD))) available To do this, we first need a kind of tagged system that will tell us when we have no method but remem ber our convention anytime we ask an object for something, it should return a procedure. Thus our way of saying no method exists also needs to be a procedure, as shown with no-method, a procedure of no arguments with access to a local frame enclosing a specia Slide 14. 4.3 Detection of methods(or missing methods) Then, to check if we have a method we take an object, such as Use (no-method) to indicate that there is no method might be returned by as k and we do the following: First, is the define n。- method argument a procedure? If it is, we assume it is a method, and we proceed. If it is not, we check to see if the value passed in is a no lambda ( tag))) method. We do this by applying no-method to get out. Check if something is a method the tag, then checking to see if the argument is eg? to it. If it is, (define (nethod? x) then we return false to indicate that no method exists for this eq?x(n。- nethod) object and message. Otherwise, we signal an error. else So why go through all of this? We need to distinguish between (err。r" Obect returned non- mes sage”x))) an error in our implementation and an error in trying to get an instance to handle a message it doesn t know about This lets us separate the details of the implementation from use of the implementation
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. 6.001 Notes: Section 14.4 Slide 14.4.1 So we have seen a first pass at building an object-oriented system, using Scheme as the base. There are a few details that we still need to clean up however. These include what to do if a class does not have a method to handle some request, the need to be able to refer to the object within methods belong to an object (i.e. an ability to recursively use methods of an object within an object), and the need to identify types of objects. Slide 14.4.2 What happens if the object doesn't know how to handle a message? We need a way to detect if we actually have a method available. To do this, we first need a kind of tagged system that will tell us when we have no method. But remember our convention: anytime we ask an object for something, it should return a procedure. Thus our way of saying no method exists also needs to be a procedure, as shown with no-method, a procedure of no arguments with access to a local frame enclosing a special symbol. Slide 14.4.3 Then, to check if we have a method, we take an object, such as might be returned by ask and we do the following: First, is the argument a procedure? If it is, we assume it is a method, and we method. We do this by applying no-method to get out the tag, then checking to see if the argument is eq? to it. If it is, then we return false to indicate that no method exists for this object and message. Otherwise, we signal an error. So why go through all of this? We need to distinguish between an error in our implementation and an error in trying to get an instance to handle a message it doesn't know about. This lets us separate the details of the implementation from use of the implementation. proceed. If it is not, we check to see if the value passed in is a no-
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 14. 4 Limitation- self-reference We have now seen an example of creating a class definition, (one of these maker- procedures), and we have seen an example of using that class definition to create a particular nstance(in this case a person). We have also seen how to separate out getting methods from actually invoking those methods to execute an action. And we have seen how to build a generic interface to the objects, so that we uniformly ask any object to do anything Slide 14.4.5 Limitation - self-reference So now we can use this. We can ask g to say "The sky is blue askq"sr·( the sk with the behavior shown nuf-said We can also ask the object its name, and we can ask the object (ask g 'CHANGE- NAME 'ishmael change its name. as shown. But in this latter case. it would be want g to""his nice if we could get the object to"say"its new name whenever it. We want a person to call its own method, but hanged its name. So doing the mutation to change the variable binding is easy. But how do we get a person to use it's own one of its methods, ask itself to do something(e.g. SAnP7 method that is, how do we get a person to recursively, with Limitation-self-reference Slide 14. 4.6 (ask g 'sAY t(the sky is blue)) Well, we have a problem here. In particular, we don 't have insic the code of this object any access to the object itself. We have ing that points to the procedure representing the object want g to SAY his new name whenever it changes which would allow us to "ask"it to do something We want a person to call its own method, but Problem: no access to the object"from inside itself Slide 14.4.7 Limitation- self-reference What we need is an explicit reference to the object itself. Our way of doing this is to add an explicit argument(called self) the sk as blue to all our methods. The goal in doing this is to allow us to have coat o mnmg sx he m hertha something within a method, it can ask itself to get other method We want a person to call its own method, but to do execute other actions Problem: no access to the" object"from inside itself! Solution: add explicit self argument to all methods
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 14.4.4 We have now seen an example of creating a class definition, (one of these maker- procedures), and we have seen an example of using that class definition to create a particular instance (in this case a person). We have also seen how to separate out getting methods from actually invoking those methods to execute an action. And we have seen how to build a generic interface to the objects, so that we uniformly ask any object to do anything. Slide 14.4.5 So now we can use this. We can ask g to say "The sky is blue", with the behavior shown. We can also ask the object its name, and we can ask the object to change its name, as shown. But in this latter case, it would be nice if we could get the object to "say" its new name whenever it changed its name. So doing the mutation to change the variable binding is easy. But how do we get a person to use it's own method, that is, how do we get a person to recursively, within one of its methods, ask itself to do something (e.g. SAY)? Slide 14.4.6 Well, we have a problem here. In particular, we don't have inside the code of this object any access to the object itself. We have nothing that points to the procedure representing the object, which would allow us to "ask" it to do something. Slide 14.4.7 What we need is an explicit reference to the object itself. Our way of doing this is to add an explicit argument (called self) to all our methods. The goal in doing this is to allow us to have an object be able to refer to itself, so that not only can it do something within a method, it can ask itself to get other methods to do execute other actions
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 14.4. 8 Better Method Convention (1)-self So here is the first change needed to make this happen. In our (detine class definition, we ensure that each method has a self rgument as its first argument, by convention (( WHOJREYOU?)(1 ambda《se1f)nam。) (lambda (self new-name)(set! Ename new-name)) (lambda (self list-of-stuff) 《dsp1a一曲ag。1nt-o-tufe UF-sND》) Slide 14 4.9 Better Method Convention(1)--self The second modification is within the CHaNge-naMe method We want the object to ask itself to say its new Thus, we ask the self object to handle a SAY mes WHOAREYOU?)(lambda (self) Ename)) (CHANGE-NAME) Notice that this should then ask the same procedure, the (lambda (selt new-name) procedure representing the object, to handle this new message, which should in turn return a new method for doing exactly that (k1EAx4时11m20m)) (lambda (self list-of-stuEE) e1se(n。- method))))) Better Method Convention(2)--ask Slide 14,4.10 Of course we will also need to modify as k. This is easy since (let ((nethod n命a9 object))) we just need to explicitly include the object as an argument when (apply nethod object args) applying the method, since each method expects an object in that r No nethod for nes gage" message) place in its argument list. Notice an important design issue here By separating out a s k from other parts of the system, and especially separating out the idea of getting a method from the idea of applying it, we have made it easier to incorporat changes such as this one Slide 14.4.11 Better Method Convention(2)--as So how does this change give us more capabilities in our system,I(define (ask object message. arga) especially our ability to ask an object to do something within the (let((method(get-method message object:))2 context of another method? Suppose we evaluate (ask g (if (method? metH apply nethod object arg CHANGE-NAME ishmael). This will first get the aLor"。 nethod£ox m9)))) method for changing names from g. That returned procedure is task g'CHAISE-RANMBE shaly then applied to the object that corresponds to g (i.e. the value <g-object> bound to g in this environment)and the argument ishmael This will first mutate the binding for fname in this environment, from george to ishmael. And then it will ask this object; the value associated with g or more particularly
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 14.4.8 So here is the first change needed to make this happen. In our class definition, we ensure that each method has a self argument as its first argument, by convention. Slide 14.4.9 The second modification is within the CHANGE-NAME method. We want the object to ask itself to say its new name. Thus, we ask the self object to handle a SAY message. Notice that this should then ask the same procedure, the procedure representing the object, to handle this new message, which should in turn return a new method for doing exactly that. Slide 14.4.10 Of course we will also need to modify ask. This is easy since we just need to explicitly include the object as an argument when applying the method, since each method expects an object in that place in its argument list. Notice an important design issue here. By separating out ask from other parts of the system, and especially separating out the idea of getting a method from the idea of applying it, we have made it easier to incorporate changes such as this one. Slide 14.4.11 So how does this change give us more capabilities in our system, especially our ability to ask an object to do something within the context of another method? Suppose we evaluate (ask g 'CHANGE-NAME ‘ishmael). This will first get the method for changing names from g. That returned procedure is then applied to the object that corresponds to g (i.e. the value bound to g in this environment) and the argument ishmael. This will first mutate the binding for fname in this environment, from george to ishmael. And then it will ask this object; the value associated with g or more particularly
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology the value associated with object in this frame, to"say"something Better Method Convention (2)--ask Slide 14,4.12 As before, let's step back from the details to consider what is being accomplished here. We have been designing an interface (apply nethod object args) for objects. We have seen that we can use a generic ask error" No ne thod for neg sage”me器&qe procedure to get methods for instances, but we have also seen that in some cases we want the methods to interact with one =>(apply +tproc p: self, ba. i me body:.] another. This requires letting an object be able to refer to itself <g-object> within a method. This led to the extension to our design that we just went through. While this was a small change in terms of a11me⊥ hae1 code, it was a big change in terms of impact on behavior of the Slide 14,4.13 Typing objects in an OOPS system One other detail that we need to consider is how to identify the type of an object. Remember in our earlier example, we wanted We want a method that acts differently depending on object to add a method to an arrogant-prof so that he would respond in (ask stad "questin ap-l"why does this code worka) one manner if the person asking a question was a student, and in a different manner if the person asking a question was a wWhy are you asking me about why does this code work I thought you published a professor How do we add the equivalent of type tags to our objects in an object-oriented system? Adding a type method Slide 14.4.14 PoIson王 One easy way to do this is to use the basic component of ar bject, namely a method. Here is an example for our person (WHOAREYOU?)(lambda(self) fname class definitio ((SAY) 1ambd《se1E1⊥st-。f一 stuEf NUF-sATD》) 1 anda《1#)香t》) o-method))))
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. the value associated with object in this frame, to "say" something. Slide 14.4.12 As before, let's step back from the details to consider what is being accomplished here. We have been designing an interface for objects. We have seen that we can use a generic ask procedure to get methods for instances, but we have also seen that in some cases we want the methods to interact with one another. This requires letting an object be able to refer to itself within a method. This led to the extension to our design that we just went through. While this was a small change in terms of code, it was a big change in terms of impact on behavior of the system. Slide 14.4.13 One other detail that we need to consider is how to identify the type of an object. Remember in our earlier example, we wanted to add a method to an arrogant-prof so that he would respond in one manner if the person asking a question was a student, and in a different manner if the person asking a question was a professor. How do we add the equivalent of “type tags” to our objects in an object-oriented system? Slide 14.4.14 One easy way to do this is to use the basic component of an object, namely a method. Here is an example for our person class definition
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 14 4.15 Now. if we check to see if someone is a person we get the Adding a type method response we expect. Clearly we could write methods for classes (define someone (makeperson'bert"sesame in which an argument is checked for its type, and different (ask someone'persen?) behaviors are used based on that type Adding a type method Slide 14.4.16 (de1n· comeon。( make-p●x。n'bert'seam) But we need to be careful! If we ask an object about a different type, we get an error( due to a lack of method) rather than the 溶k。mene' person?) behavior we wanted, namely returning false to say that the object is not of this ty (ask someone profe no nethod tor pr。fe器a Type D to debug Slide 14.4.17 Adding a type method To fix this, we need to add one more detail, namely a way of (define someone (make-person 'bert sesame)) asking if an object is of a particular type. This is shown here (ask someone 'person?) This procedure can be used to check in an object is of a particular type, but will return true or false, rather than failing due to a lack of method othod for professor? in bert oe D to debug error, o to return back t。Ri。。p (detine (is-a object type-pred) #f)),3.Ject type-pred Adding a ty pe method Slide 14 4.18 (define someone (make-person 'bert 'sesame)) The point of this last example is to show that we can add the (ask someone 'per son? same abilities we saw earlier with tagged data types. We simply lat our mechanism for checking type tags consistent with the object-oriented framework. But with this Type d to debug error,o to return back to REP loop ability, we can now inherit all the power we saw earlier of define (is-a object type-pred) dispatching on type, in this case to different objects ( let((nethod (get-method type-prod objoct)))
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 14.4.15 Now, if we check to see if someone is a person, we get the response we expect. Clearly we could write methods for classes in which an argument is checked for its type, and different behaviors are used based on that type. Slide 14.4.16 But we need to be careful! If we ask an object about a different type, we get an error (due to a lack of method) rather than the behavior we wanted, namely returning false to say that the object is not of this type. Slide 14.4.17 To fix this, we need to add one more detail, namely a way of asking if an object is of a particular type. This is shown here. This procedure can be used to check in an object is of a particular type, but will return true or false, rather than failing due to a lack of method. Slide 14.4.18 The point of this last example is to show that we can add the same abilities we saw earlier with tagged data types. We simply need to ensure that our mechanism for checking type tags is consistent with the object-oriented framework. But with this ability, we can now inherit all the power we saw earlier of dispatching on type, in this case to different objects