(load "~cs61a/lib/obj.scm") ; Lecture 14 ; Announcements ; ; Project 2 due Thursday. Get crackin'! ; ; Project 1 grades should be up. Please e-mail your reader and your TA if ; you have not gotten your grade yet. Also, if you have any complaints or ; regrade requests, e-mail your reader and your TA. ; ; Regrade/complaint deadline for hw1a, hw1b, hw2a, hw2b, proj1, mt1 is ; MONDAY at 11 AM. To make a complaint or request a regrade, e-mail your ; reader AND your TA, with a brief explanation of what you think is wrong. ; We will only regrade your assignment once. Regrade grades are FINAL. ; We will regrade your assignment COMPLETELY. Therefore there is the ; possibility that your grade will go DOWN. Make sure to check that this ; won't happen before you request one. ; ; hw3a, hw3b due tonight at midnight ; hw4a assigned, hw4b to be posted later tonight ; Object oriented programming: ; Main aspects: ; * Message passing: ; The user, as well as objects themselves, can ask objects to do stuff. ; * Local state: ; An object can remember stuff about its own past history. ; * Inheritance: ; One object type can be just like another except for a few differences. ; We affectionately call object-oriented programming OOP. (define-class (square side-length) (method (area) (* side-length side-length)) (method (perimeter) (* 4 side-length))) (define sq (instantiate square 2)) (ask sq 'area) (ask sq 'perimeter) (ask sq 'side-length) (define-class (complex real-part imag-part) (method (magnitude) (sqrt (+ (* real-part real-part) (* imag-part imag-part)))) (method (angle) (atan (/ imag-part real-part)))) (define z (instantiate complex 3 4)) (ask z 'magnitude) (ask z 'angle) (ask z 'real-part) (ask z 'imag-part) ; The above example shows how to define the *class* complex. ; It also shows how to create an *instance* of the class. ; We can pass *messages* to objects using (ASK OBJ MSG). ; When we send a message to an object, it carries out a *method*. ; real-part and imag-part are called the *instantiation variables*. ; Instantiation variables are also accessible via messages. ; "OOP buzzwords": ; class = a particular object type ; instance = a particular object ; Nothing new is happening here, it's just a new notation. Essentially ; the OOP extension to Scheme makes it an entirely different programming ; language. ; !!!!! ; BY THE WAY (THIS IS IMPORTANT), in order to use our OOP extension to ; Scheme, you must load the file ~cs61a/lib/obj.scm ; !!!!! ; OK, now something new: (define-class (counter) (instance-vars (count 0)) (method (next) (set! count (+ count 1)) count)) (define c1 (instantiate counter)) (ask c1 'next) (ask c1 'next) (define c2 (instantiate counter)) (ask c2 'next) (ask c1 'next) (ask c2 'count) (ask c1 'count) ; set! is a special form ... read about it in the book. ; Each counter has its very own unique *instance variable*. Just like ; instantiation variables, instance variables can be accessed via messages. ; Instance variables are similar to instantiation variables, but they are ; not exactly the same. (define-class (counter count2) (instance-vars (count 0)) (method (next) (set! count2 (+ count2 1)) (set! count (+ count 1)) (list count count2))) (define c1 (instantiate counter 5)) (ask c1 'next) (define c2 (instantiate counter 100)) (ask c2 'next) (ask c1 'next) (ask c2 'next) ; We have instance variables, which are UNIQUE to EACH instance. ; However, we might also want *class variables*, which are SHARED ; by each instance. (define-class (counter) (instance-vars (count 0)) ; local, unique to each instance of counter (class-vars (total 0)) ; global, shared by each instance of counter (method (next) (set! count (+ count 1)) (set! total (+ total 1)) (list count total))) (define c1 (instantiate counter)) (ask c1 'next) (ask c1 'next) (define c2 (instantiate counter)) (ask c2 'next) (ask c1 'next) (ask c1 'count) (ask c2 'count) (ask c1 'total) (ask c2 'total) ; class variables can also be accessed via messages. ; Now we'll look at inheritance ... ; With inheritance, we have CHILD classes and PARENT classes. ; The PARENT class is for more GENERAL objects, and the CHILD class ; is for more SPECIFIC objects. The CHILD class INHERITS some methods ; from the PARENT class, but may have some unique facets. ; The class of BMW cars is a child class of the general automobile class. ; The class of forks is a child class of the silverware class. ; The class of mammals is a parent class of the class of humans. ; Now consider this person class: (define-class (person name) (method (say stuff) stuff) (method (ask stuff) (ask self 'say (se '(would you please) stuff))) (method (greet) (ask self 'say (se '(hello i am) name)))) (define marc (instantiate person 'marc)) (ask marc 'say '(good morning)) (ask marc 'ask '(open the door)) (ask marc 'greet) ; Notice that an object can refer to itself via SELF. (define-class (pigger name) (parent (person name)) (method (pigl wd) (if (member? (first wd) '(a e i o u)) (word wd 'ay) (ask self 'pigl (word (bf wd) (first wd))))) (method (say stuff) (if (atom? stuff) (ask self 'pigl stuff) (map (lambda (wd) (ask self 'pigl wd)) stuff)))) (define porky (instantiate pigger 'porky)) (ask porky 'say '(good morning)) (ask porky 'ask '(open the door)) ; Crucial point: the pigger class doesn't have the ASK method. ; When we ask a pigger to ASK something, it uses the ASK method in ; its parent (person) class. ; Also, IN THIS CASE, when the parent's ask method says ; (ask self 'say ...), it uses the say method from the pigger class, ; not from the person class. So Porky speaks Pig Latin even when ; asking something. ; Now consider this worker class: (define-class (worker) (instance-vars (hunger 0)) (class-vars (all-workers '()) (work-done 0)) (initialize (set! all-workers (cons self all-workers))) (method (work) (set! hunger (+ 1 hunger)) (set! work-done (+ 1 work-done)) 'whistle-while-you-work)) ; Initialize does stuff every time an instance is created, and only ; when an instance is created. (define grumpy (instantiate worker)) (ask grumpy 'work) (ask grumpy 'work) (ask grumpy 'all-workers) (ask grumpy 'hunger) (ask grumpy 'work-done) (define sleepy (instantiate worker)) (ask sleepy 'work) (ask sleepy 'all-workers) (ask sleepy 'hunger) (ask sleepy 'work-done) ; (define-class (TA) ; (parent (worker)) ; (method (work) ; (ask self 'work) ; WRONG! INFINITE LOOP! Why? ; '(let me help you with that box and pointer diagram)) ; (method (grade-exam) 'A+)) (define-class (TA) (parent (worker)) (method (work) (usual 'work) '(let me help you with that box and pointer diagram)) (method (grade-exam) 'A+)) (define ramesh (instantiate TA)) (ask ramesh 'work) (ask ramesh 'work) (ask ramesh 'grade-exam) (ask ramesh 'work-done) (ask ramesh 'hunger) (ask grumpy 'work-done) (ask grumpy 'all-workers) ; Calling usual is just like doing (ask self ...) with the same arguments, ; excep that only methods defined within an ancestor class (parent, grand- ; parent, etc.) are eligible to be used. ; Why do we use the word USUAL? We are thinking of subclasses as ; specializations. USUAL means that the child can explicitly decide ; to do something in the USUAL, parent-like, general way, instead of ; in its own SPECIALIZED way. ; Default methods ... ; Will over default methods in the next lecture.