1
6.001 SICP
Object Oriented Programming, Part 2
• from Basic Objects ...
• ... to Object Orientation with Inheritance
• Details -- A Scheme OOP System
• Example: speakers, lecturers, and singers
2
Elements of OOP
•Class:
• specifies the common behavior of entities
•Instance:
• A particular object or entity of a given class
3
Space War Class Diagram
SHIP
position: velocity:
num-torps:
POSITION VELOCITY MOVE
SHIP? ATTACK DISPLAY CLOCK-TICK EXPLODE
PLANET position: POSITION PLANET? DISPLAY CLOCK-TICK TORPEDO
position: velocity:
target: proximity-fuse: TORPEDO?
POSITION VELOCITY MOVE
DISPLAY CLOCK-TICK
• Ships and torpedos have some behavior that is the same– is there are way to capture this commonality?
4
Space War Class Diagram with
Inheritance
MOBILE - THING
position: velocity:
MOBILE-THING?
POSITION VELOCITY MOVE
SHIP num-torps: SHIP? ATTACK DISPLAY CLOCK-TICK EXPLODE TORPEDO
target: proximity-fuse: TORPEDO? DISPLAY CLOCK-TICK
is-a is-a
•SHIPclass is a specialization or sub-classof the MOBILE - THINGclass
•SHIPis-aMOBILE- THING •SHIPinheritsthe state and
behavior of MOBILE - THING •MOBILE - THINGclass is a super-class
of the SHIPand TORPEDOclasses
PLANET position: POSITION PLANET? DISPLAY CLOCK-TICK
has-a target
5
How build an OOP system in Scheme?
•Objects: as procedures that take messages •Instances have Identity: in sense of eq?
– Object instances are unique Scheme procedures
•Local State: gives each object (each instance of a class) the ability to perform differently
– Each instance procedure has own local environment
•Classes: Scheme make-<object>procedures. •Methodsreturned in response to messages:
– Scheme procedures (take method-dependent arguments)
•Inheritance Ruletelling what method to use – Conventions on messages & methods
6
Steps toward our Scheme OOPs:
1. Basic Objects
A. messages and methods convention B. selfvariable to refer to oneself
2. Inheritance
A. internal superclass instances, and
B. match method directly in object, or get -method from internal instance if needed
C. delegation: explicitly use methods from internal objects
7
Today's Example World: Speakers,
Lecturers, and Singers
SPEAKER name: NAME CHANGE-NAME SAY
8
1. Method convention
• The response to every messageis a method
• A methodis a procedure that can be applied to actually do the work
(define (make -speakername) ; specifies the speakerclass
(lambda (message)
(cond ((e q? message ’NAME) (lambda () name))
((e q? message ’CHANGE-NAME)
(lambda (new- name) (set! name new-name)))
((e q? message ’SAY)
(lambda (list -of-stuff)
(display-message list- of-stuff)
'NUF-SAID))
(else (no -method)))))
9
Alternative
case
syntax for message match:
•case is more general than this (see Scheme manual), but our convention for message matching will be:
(case message
((< msg -1>) <method -1>)
((< msg -2>) <method -2>)
...
((< msg -n>) <method -n>)
(else <expr>))))
10
Method convention – with case syntax
• The response to every messageis a method
• A methodis a procedure that can be applied to actually do the work
(define (make-speaker name) (lambda (message)
(case message
((NAME) (lambda () name)) ((CHANGE -NAME)
(lambda (new-name) (set! name new-name))) ((SAY)
(lambda (list -of-stuff)
(display -message list-of-stuff)
'NUF-SAID)) (else (no-method)))))
p: () body: name
p: (new-name) body: (set! ...)
11
How make and use the object?
• Making an object instance
(define s (make -speaker ’george))
• Using the object instance (painful way)
((s 'NAME))
==>(#[proc p:() body:name]) ;apply to no args
==> george
Two things going on:
1. method lookup – (s 'NAME)==> <method>
2. method application – (<method>) ==> <result>
12
Using the object – easier way
• method lookup:
(define (get-method message object) (object message))
• "ask" an object to do something
-combined methodretrieval and applicationto args.
(define (ask object message . args)
(let ((method(get -method message object))) (if (method? method)
(apply methodargs )
(error "No method for message" message))))
13 (ask s ’NAME) ==> ((s 'NAME)) ==> george
(define s (make-speaker ’george))
Example
GE s: make- speaker: ...
p: message body: (case ...) E3
name: george
E4
message: NAME
p: () body: name
E5
name | E5
14
Detection of methods (or missing methods):
• Use (no-method)to indicate that there is no method
(define no-method
(let ((tag (list ’NO-METHOD))) (lambda () tag)))
• Check if something is a method:
(define (method? x)
(cond ((procedure? x) #T) ((eq? x (no-method)) #F) (else
(error "Object returned non-message" x))))
15
Limitation – self-reference
(ask s 'SAY '(the sky is blue)) the sky is blue
=> nuf-said
(ask s 'CHANGE-NAME 'fred)
– want s to "SAY" his new name whenever it changes
• We want a speaker to call its own method, but ...
•Problem: no access to the "object" from inside itself! •Solution: add explicit selfargument to all methods
16
Better Method Convention (1) --
self
(define (make-speaker name) (lambda (message)
(case message
((NAME) (lambda (self) name)) ((CHANGE -NAME)
(lambda (self new-name) (set! name new -name)
(ask self ’SAY (list ’call ’me name)))) ((SAY)
(lambda (self list-of-stuff) (display -message list-of-stuff) 'NUF-SAID))
(else (no-method)))))
17
Better Method Convention (2) --
ask
(define (ask object message . args)
(let ((method (get -method message object))) (if (method? method)
(apply method
object
args)(error "No method for message" message))))
(ask s ’CHANGE -NAME ’fred)
==>(apply #[proc p:self,new-name body:...]
<s-object>
'fred )
==> (ask <s-object> ‘say …) call me fred
nuf-said
18
Steps toward our Scheme OOPs:
1. Basic Objects
A. messages and methods convention B. selfvariable to refer to oneself
2. Inheritance ç
A. internal superclass instances, and
B. match method directly in object, or get -method from internal instance if needed
C. delegation: explicitly use methods from internal objects
19
Example World: Lecturer Subclass
SPEAKER name: NAME CHANGE-NAME SAY
LECTURER LECTURE
is-a
(define d (make-lecturer 'duane))
(ask d 'SAY '(the sky is blue))
the sky is blue
==> nuf-said
(ask d 'LECTURE '(the sky is blue))
therefore the sky is blue
==> nuf-said
A lecturer prefaces all lecture material with "Therefore"
20
2. Approach: Inheriting Superclass Methods
• Subclass will Inherit superclass behavior by adding an "internal" instanceof the superclass
• E.g. lecturerwill have an internal speakerobject • If message is not recognized, pass the buck
(define (make-lecturer name) ;subclass (let ((int-speaker (make-speaker name))) ; superclass
(lambda (message) (case message
((LECTURE) ...) ;new method
(else (get-method message int-speaker))))))
(ask d 'SAY ’(the sky is blue)) the sky is blue
21
How the
internal object
works:
GE make- speaker: ...
make- lecturer: ... e:
E1 name: e r i c
p: m s g body: (case ...) E3
name: e r i c
p: m s g body: (case ...)
(define e (make-lecturer ‘e r i c))
Frame E1 created by application of make- lecturer. Frame E2 created by let inside make- lecturer.
Frame E3 created by application of make- speaker (inside make -lecturer)
dashed object is int- speaker
solid object is our new lecturer object(with an internal speakerinside) E2
int-speaker:
22
2. Approach: Delegation to Superclass
• Can change or specialize behavior of methods:
• Internal objectacts on behalf of the lecturerobject by delegation
(define (make -lecturer name)
(let ((int- speaker (make-speaker name)) ) (lambda (message)
(case message
((LECTURE) ;now implement this... (lambda (selfstuff)
(delegate int -speakerself’SAY (cons ’therefore stuff)))) (else (get- method message int-speaker))))))
(ask e’LECTURE ’(the sky is blue))
therefore the sky is blue
23
Delegate vs. Ask
(define (delegate tofrommessage . args) (let ((method (get -method message to)))
(if (method? method)
(apply method from args) ;frombecomes self (error "No method" message))))
(define (ask objectmessage . args)
(let ((method (get -method message object))) (if (method? method)
(apply method objectargs) ;objectbecomes self (error "No method for message" message))))
24
Example: An Arrogant-Lecturer Subclass
SPEAKER name: NAME CHANGE-NAME SAY
LECTURER LECTURE
is-a
(define e
(make-arrogant-lecturer ‘eric))
(ask e 'SAY '(the sky is blue)) the sky is blue obviously
(ask e 'LECTURE '(the sky is blue)) therefore the sky is blue obviously
An arrogant lecturer ends everything he/she says with "obviously"
ARROGANT-LECTURER SAY
25
Example: An Arrogant-Lecturer Subclass
(define (make-arrogant-lecturer name) ;subclass (let ((int-lecturer(make-lecturer name)));superclass
(lambda (message) (case message
((SAY)
(lambda (selfstuff)
(delegate int-lecturerself
’SAY (append stuff ’(obviously))))) (else (get-method message int-lecturer))))))
(ask e’LECTURE ’(the sky is blue))
therefore the sky is blue ; BUG! (obviously)
26
Where is the bug?
• Problem is notin the new arrogant -lecturer subclass! • Arrogant -lecturer changed it's SAY method with the
expectation that everythingan arrogant -lecturer says will be modified
• The bug is in the lecturer class! • Delegated SAY to internal speaker
• Should have asked whole self to SAY
• But.... the arrogant -lecture SAY method didn't get called when we asked arrogant -lecturer to LECTURE
• With askit is possible for a superclass to invoke a subclasses's method (as we want in this case)!
27
Fixing the Bug: ask
vs.
delegate
(define (make-lecturer name)
(let ((int-speaker (make-speaker name))) (lambda (message)
(case message ((LECTURE)
(lambda (self stuff)
;bug (delegate int-speaker self ’SAY ;bug (append ’(therefore) stuff))
(ask self ’SAY
(append ’(therefore) stuff)))) (else (get-method message int-speaker))))))
(define e (make-arrogant-lecturer ‘ eric))
(ask e’LECTURE ’(the sky is blue)) therefore the sky is blue obviously
28
Steps toward our Scheme OOPs:
1. Basic Objects
A. messages and methods convention B. selfvariable to refer to oneself
2. Inheritance
A. internal superclass instances, and
B. match method directly in object, or get -method from internal instance if needed
C. delegation: explicitly use methods from internal objects
3. Multiple Inheritance ç
29
Example: A Singer, and A Singing
Arrogant-Lecturer
SPEAKER name: NAME CHANGE-NAME SAY
LECTURER LECTURE
is-a
A singer is not a speaker.
A singer has a different SAY that always ends in "tra la la".
A singer starts to SING with "the hills are alive"
ARROGANT-LECTURER
SAY
is-a
SINGER
SAY SING
S-A-L
is-a is-a
30
3. Multiple Inheritance
• The singer as a "base" class (no superclasses ):
(define (make-singer) (lambda (message)
(case message ((SAY)
(lambda (self stuff) (display -message
(append stuff ’(tra la la)))) ((SING)
(lambda (self)
31
A Singing Arrogant Lecturer
• Now we’ll create a singing arrogant lecturer:
(define (make-s-a-l name) (let ((int-singer (make-singer))
(int-arrognt (make-arrogant -lecturer name))) (lambda (message)
(find -methodmessage int-singerint-arrognt))))
(ask zoe ’SING)
the hills are alive tra la la
(ask zoe ’LECTURE ’(the sky is blue)) therefore the sky is blue tra la la
32
Multiple Inheritance – Finding a Method
• Just look through the supplied objects from left to right until the first matching method is found.
(define (find-method message . objects) (define (try objects)
(if (null? objects) (no-method)
(let ((method (get -method message (car objects)))) (if (not ( eq? method (no-method)))
method
(try ( cdr objects)))))) (try objects))
33
Unusual Multiple Inheritance
• We could build an OOPS with lots of flexibility - suppose we want to pass the message on to multipleinternal objects?
(define (make -s-a-l name)
(let ((int- singer(make-singer name))
(int- arrognt(make-arrogant -lecturer name))) (lambda (message)
(lambda (self . args)
(apply delegate- to-all (list int- singer int- arrognt)
self args )))))
(ask zoe ’SAY ’(the sky is blue))
the sky is blue tra la la the sky is blue obviously tra la la the sky is blue obviously obviously tra la la
...
34
Unusual Multiple Inheritance: delegate -to-all
(define (delegate -to-all to-list from message . args) (foreach
(lambda (to-whom)
(apply delegate to-whom from message args )) to-list))
35
Summary: our Scheme OOP system
1. Basic Objects
A. all messages return a method B. selfvariable to refer to oneself C. run with ask
2. Inheritance
A. internal superclass instances, and
B. match method in case, or get-methodfrom internal instance
C. delegate: explicitly use methods from internal objects
3. Multiple Inheritance
A. find-methodto get first matching method
36 6.001 SICP Recitation problem Oct. 21, 1999 • Suppose we add a type predicate to our basic speaker class:
(define (make-speaker name) (lambda (message)
(case message
((SPEAKER?) (lambda () #T)) ;fixed typo on handout ;relace NAME? w/ SPEAKER?
((NAME) ...)
((SAY) ...)
(else (no-method)))))
• What is returned by