CS212 Lecture 4/2/98 by Melissa Ho

----------------------------------------------------------------



Object-Oriented Programming:



  * A technique for organizing large systems, for example

    - Window system

    - Simulation (we will do a game with interacting autonomous agents)



IDEA:

  * Decompose your problem into OBJECTS and OPERATIONS on them.

      (note we did this also with generic operations,

       but now the objects have local state, and more...)



  * Have a CLASS HIERARCHY which specifies the relation between types.

    > CLASS = a kind of object (similar to a type)

      "Animal", "Bird", "Dinosaur", like that.

    > INHERITANCE - inherit state and operations

    > "A duck is a kind of bird"

      * DINOSAUR = subclass = more specific kind of thing

      * ANIMAL = superclass = more general kind of thing.

    > Subclasses may have more or different operations:

      * ANIMALs might or might not be cold-blooded

      * DINOSAURs are cold blooded (at least acording to some

        theories! To heck with Jurassic Park) 



  <thing>

     |

     |

  <animal>

     |

     |

  <dinosaur>



MANTRA: 

  An object of a subclass can be used ANYWHERE that an object of a

  superclass can be used.



   * A program which can manipulate groups of animals

     can therefore also manipulate flocks of dinosaurs.



----------------------------------------------------------------

There are two metaphors of OO programming:

  * Message Passing - send message to the object

      "Fly south for the winter!"

      (send big-bird 'fly 'south)

  * Generic Functions - Functions that handle different types of objects.

      (fly big-bird 'south)



There's still debate on which is "better"



We use GENERIC FUNCTIONS because they fit Dylan better, and they

support "multimethods", which are useful.



----------------------------------------------------------------------



Some Terminology:

  CLASS    = kind of thing

             "Dinosaur"

  INSTANCE = An individual object (entity) of some class.

             "Dino", "Barney"

  METHOD   = Code that operates on specific classes.  A function.

             "how dinosaurs sing"



[Note: the question *why* dinosaurs might sing is reserved for philosophers]





You should all be familiar with classes already.



To review

(define-class <animate> (<object>)

  (weight type: <number> init-keyword: size: init-value: 10)

  (hunger type: <number> init-keyword: hunger: init-value: 0))



(define-class <dog> (<animate>)

  (name type: <symbol> init-keyword: name:))



(define (bismark <dog>) (make <dog> name: 'bismark))



For example,



(name bismark)   ==> bismark

(weight bismark) ==> 10 [why?]

We can use set! to change the value of a slot in an instance

(set! (weight bismark) 20)



----------------------------------------------------------------------

OPERATIONS:

  * GENERIC OPERATIONS using generic functions, as we covered earlier

     in the semester.  Collection of functions, or "methods" that

     together implement some operation



  * each function is a type-specific "method" that handles specific

      class(es), given by its parameter list



(define-generic-function eat (me food))

(add-method eat

  (method ((me <animate>) (food <symbol>))

    (cond ((member? food '(salad fruit tofu))

           (set! (hunger me) (- (hunger me) 1)))

          ;; CS212 is not a class in nutrition

          ((member? food '(donut chips))

           (set! (hunger me) (- (hunger me) 2))))))

(add-method eat

    (method ((me <dog>) (food <symbol>))

       (bind (((last-hunger <number>) (hunger me)))

         (next-method me food)

         (cond ((>= (hunger me) last-hunger)

                (print (name me))

                (print " is hungry.  Feed me something good."))))))



Note: the second function here has the access to

the instance variables of <dog> (NAME) and of its

superclass <animate> (HUNGER in this case).  Why?  Because of the type of

the parameter.  Cant generally assume that something of type <animate> has

the slots of a <dog>.





>> Leave it on board.



  * This generic function has two methods, one that operates on

    instance of class <animate>, and one that operates on instances

    of class <dog>.



Now, we can do:





  (eat bismark 'dry-bone)



The generic function eat uses the class hierarchy to find the most

specific method that applies

  There is a method for instances of class <dog>, and bismark is an

  instance of that class, so that method is applied.  (This is the

  same mechanism that we saw for generic function operating on

  values in general).



If there had been no method for <dog>, we'd try <animate>, which is

the direct superclass (and so on up the hierarchy)



NOTE:

  * The most specific method is used

  * The other ones are generally ignored (except when explicitly

    invoked, using next-method).



So, the second function gets invoked because <dog> is more specific

than animate with respect to the given argument, bismark (which is of

class <dog>).  This function binds a local variable and then calls the

function next-method --- which is a special function that means "run

whatever method would have run if the method currently running had not

been part of the generic function".  In this case, that means call the

function with parameter of type <animate> (as <animate> is the closest

superclass of <dog>).  This function checks whether dry-bone relieves

hunger, it does not, so it just returns.  Then the method for class

<dog> continues running (the next-method has returned), and as the

hunger value has not decreased, prints out:



  bismark is hungry. feed me something good.



We will cover next-method more in the next few lectures, so if it does

not make total sense at the moment, don't worry.  At least this simple

example should make sense.



Thus, note that with classes and methods we can either replace

functionality (a <dog> method that is special and does something

totally different than the <animate> method) or we can do something

slightly different (using next-method to do what would have happened,

before or after doing something else).



----------------------------------------------------------------------



OOP and Generic Operations



OOP is a technique for organizing "large" systems. (Note: this makes

it hard for us to get across in lecture many of the advantages -- we

can look at the techniques here, but much of the real learning will

come in the problem set which is a large system.)



Builds on the notion of generic operations that we covered earlier in

the semester.  Conceptually a table of procedures, indexed by

operations and data types.



In Dylan we use a generic functions style of type dispatching.



The NEW IDEAS in OOP (beyond generic functions) are:



  1) objects have local state variables (called slots), which are only

     accessible in certain contexts -- based on the type of the

     parameter/variable that names an object



  2) types of objects (classes) are arranged in a hierarchy, from

     which they inherit their "behavior" (their slots and functions).



A key principle in OOP is that a subclass should build on and modify

the behavior of its superclass(es).



Thus the central design issue in an OOP style of programming is to

come up with a hierarchy of classes such that the objects of each

class can build on the behavior of their superclasses (the idea is to

have an effective way of SHARING code between objects of different

classes).



-------------------------------------------------------------------

Another example, 





(define-class <vehicle> (<object>)

  (location <symbol> init-value: 'here) 

  (speed <number> 0))



(define-class <car> (<vehicle>)

  (fuel <number> init-value: 0))

(define-class <rocket> (<vehicle>)

  (fuel <number> init-value: 0)

  (altitude <number> init-value: 0))



(define-class <bicycle> (<vehicle>))



Note: single inheritance, so class hierarchy is a tree



<object>

   |

   |

<vehicle>

   |

   |

   |-------------------

   |     |            |

 <car> <rocket>  <bicycle>



(define-generic-function accelerate (v a))

;; A1 <vehicle>

(add-method accelerate

            (method ((v <vehicle>) (a <number>))

              ;; Could also use: (set! (speed v) (+ (speed v) a))

              (speed-setter v (+ (speed v) a))))

;; A2 <rocket>

(add-method accelerate

            (method ((r <rocket>) (a <number>))

              (cond ((> (fuel r) 0)

                     (print "Whoosh...")

                     (next-method r a))

                    (else: (print "You lose. No gas.")))))

;; A3 <bicycle>

(add-method accelerate    

            (method ((b <bicycle>) (a <number>))

              (print "Dream on.")))



Some things to note about this generic function



 o A method can access only those slots of a class and its

   superclasses.  For instance, the first method (A1) can access the speed

   slot, of <vehicle>, as can the second method (A2).  But the first method

   cannot access the fuel slot of <rocket>.  This is because <vehicle>

   is a  superclass of <rocket>.



 o The second function uses next-method -- which is

   valid because there is a next function (the one for <vehicle>).

   The "next" function is defined solely by the class hierarchy.



-------------------



Now we can create some instances of objects of these classes, and call

accelerate.



(define schwinn (make <bicycle>))

(define saturn-v (make <rocket> fuel: 10 altitude: 100000))

(define chevy (make <car> fuel: 10 location: 'there))



Each instance has all of the slots of the given class and its

superclasses.  Thus, 



schwinn has slots: location= here, speed=0

saturn-v has slots: location=here, speed=0,fuel=10,altitude=100000

chevy has slots: location=there, speed=0, fuel=10



[Note: this question is the prelim 2 equivalent of "what is the value

 of this expression".]



If we evaluate



(accelerate chevy 10)



The most specific applicable function of the generic is the one for

<vehicle> (because there is no method for class <car>, and the next

most specific class is <vehicle> for which there is a method).



This function increments the speed slot by 10.



If we evaluate



(accelerate schwinn 10)



The most specific method is the one for <bicycle> which simply prints

out the string "Dream on"



If we evaluate



(accelerate saturn-v 10)



The most specific method is the one for <rocket> which checks if the

fuel level is > 0 (which it is for this instance) and if so print

"Whoosh" and then calls next-method.  Recall, next-method means

re-invoke the generic (in this case accelerate) with the specified

arguments, but as if the currently running function were *not* part of

the generic function(that is run the next most specific function; the

one that would have run if the current function had not been part of

the generic function).



-----------------------------------------------------------------



The above example illustrates three different means of using generic

functions and the class hierarchy to extend or modify the behavior of

superclasses.



 o A class can simply inherit the behavior of its superclass (e.g.,

   above an instance of class <car> simply inherits the behavior of a

   <vehicle>)



 o A class can replace the behavior of its superclass, by defining

   a class-specific method.  This is sometimes called shadowing the

   behavior of the superclass (e.g., above an instance of class

   <bicycle> has a completely different behavior than the superclass

   <vehicle>)



 o A class can modify the behavior of its superclass, by defining a

   class-specific method that uses next-method (e.g., above an instance of

   class <rocket> has a behavior that modifies that of a general

   <vehicle>).  There are 3 common patterns of such modified behavior:

      a BEFORE method does some computation and then a next-method call

      an AFTER method does a next-method call and then some computation

      an AROUND method does computation, next-method, more computation





-------------------------------------------------------------------



Summary:

  * Object Oriented Programming

    - Organizing large systems

    - Operations / Generic Functions

    - Objects / Classes -- with local state variables (SLOTS)

    - Inheritance Hierarchy



CLASS (similar to a type declaration)

    - list of slots, each is (type name init-value)

    - initialization function, called with the new instance

    - superclasses (if any)



INSTANCE:

    - Created by MAKE

    - Each one has some local data, stored in SLOTS

    - In addition to its own slots of given class it has all of the

      slots of all its superclasses. 





Methods are type-specific operations (functions) which generic

functions call - The generic function 'fly' might have methods for

<bird> and <airplane> and <penguin>



next-method gives ability to build on/modify behavior of superclasses.





-------------------------------------------------------------



CS Joke of the day:



[Xerox PARC (Palo Alto Research Center) is the research arm of Xerox

 Corp, where they invented the pesonal computer, the graphical user

 interface, the local area network, and the copying machine. ]



Q: What's the difference between Jurassic Park and Xerox PARC? 



A: One's a high-tech theme park for dinosaurs. 

   The other's a movie by Steven Speilberg.