I. Concepts for Objects and Classes (5-5.2) A. basic concepts of object-oriented programming (5.1) What were the key ideas from the chapter on interpreters? 1. simple picture: object, state, methods ------------------------------------------ OBJECTS AND CLASSES (5) A STACK OBJECT ______________________ | top-index [ 2 ] | | stk [ * ] | | | | | __v______ push! | | | | | |_______| | | | 3 | pop! | |_______| | | | 4 | | | |_______| top | | 2 | | | |_______| | | | |______________________| state = instance variables methods (operations) = code that responds to messages instance = object ------------------------------------------ What's the C++ jargon for "instance variable"? For method? What's an object like that we've already seen? 2. classes ------------------------------------------ TWO OBJECTS OF THE SAME CLASS ___________ ___________ | | | | | top-index | | top-index | | [ 1 ] push! | [ 2 ] push! | stk[ * ] | | stk[ * ] | | | | | | | | __v__ | | __v__ | | |___| pop! | |___| pop! | |___| | | |_3_| | | |_2_| | | |_4_| | | |_7_| top | |_2_| top | | | | |___________| |___________| def: an *instance variable* is private to each def: a *class variable* is shared by def: *class* is used to mean: ------------------------------------------ What's the C++ jargon for instance variables? What's the C++ jargon for class variable? 3. message = method name + arguments ------------------------------------------ MESSAGE PASSING ___________ ____________ | | | \ / | __ | | | \ / | | push! | \/ | __ | | | push! 1 | | | |__________| | pop! \ \ \ | | | | | top | | |___________| object ^ message ^ def: A set of objects that behave the same in response to sequences of messages form an ------------------------------------------ What does the message do? What's all this good for? B. inheritance (5.2) 1. example ------------------------------------------ INHERITANCE EXAMPLE (FIG 5.3) class point extends object field x field y method initialize(initx, inity) begin set x = initx; set y = inity end method move(dx,dy) begin set x = +(x,dx); set y = +(y,dy) end method get_location () list(x,y) class colorpoint extends point field color method set_color (c) set color = c method get_color () color Terms: ------------------------------------------ 2. what is inherited ------------------------------------------ INHERITANCE OF DATA AND METHODS A subclass inherits both: - instance variables, and - methods from its ancestor classes. ------------------------------------------ What are the instance variables in an instance of class colorpoint? What methods does such an instance possess? 3. scope and shadowing a. for fields ------------------------------------------ SCOPE OF FIELD DECLARATIONS Region of field declaration: Scope of a field declaration: ------------------------------------------ What kind of privacy do fields have in this language? Would it be sensible to prohibit subclasses from accessing instance variables? ------------------------------------------ SHADOWING OF FIELD DECLARATIONS class meter extends object field count method initialize() set count = 0 method bump() set count = add1(count) method value() count method mvalue() count class gague extends meter field count method initialize() set count = 100 method value() count let g = new gague() in begin send g bump(); list(send g value(), send g mvalue()) end ------------------------------------------ What does this return? Why? b. for methods i. overriding ------------------------------------------ METHOD OVERRIDING Methods don't have satic scope send o m(arg) Overriding: - method with same name in a subclass *overrides* it, in that the subclass method is run instead on subclass objects Example: let g = new gague() in begin send g bump(); list(send g value(), send g mvalue()) end ------------------------------------------ What methods of meter are overridden in gague? ii. dynamic dispatch ------------------------------------------ DYNAMIC DISPATCH (FIG on p. 176) class c1 extends object method initialize () 1 method m1 () 1 method m2 () send self m1() class c2 extends c1 method m1 () 2 let o1 = new c1() o2 = new c2() in list(send o1 m1(), send o2 m1(), send o2 m2()) ------------------------------------------ iii. self What is self in Java? C++? What is returned by the first method send? the second? The third? ------------------------------------------ EXAMPLE WITH SELF (FIG 5.4) class c1 extends object method initialize () 1 method m1 () 1 method m2 () 100 method m3 () send self m2() class c2 extends c1 method initialize () 1 method m2 () 2 let o1 = new c1() o2 = new c2() in list(send o1 m1(), send o1 m2(), send o1 m3(), send o2 m1(), send o2 m2(), send o2 m3()) ------------------------------------------ iv. super ------------------------------------------ SUPER CALLS Super is like sending to self, but starts Example, for colorpoint: method initialize(initx, inity, initcolor) begin super initialize(initx, inity); set color = initcolor end ------------------------------------------ C. polymorphism ------------------------------------------ POLYMORPHISM def: code is *polymorphic* if it can work on objects of different classes <> let p = if random(2) then new point(3, 4) else new colorpoint(10, 20) in begin send p move(3,4); send p get_location() end ------------------------------------------ II. Language for OOP (5.3) A. syntax ------------------------------------------ SYNTAX ::= {}* ::= class extends {field }* {}* ::= method ( {}*(,) ) ::= ... | ------------------------------------------ What is the extends for in a class declaration? What do we do if the class doesn't have a superclass? Does it ever make sense to omit new fields? New methods? What kinds of new expressions do we need? What would be the abstract syntax appropriate for these? B. semantics 1. domains ------------------------------------------ DOMAINS Expressed-Value = Number + ProcVal + Obj + List(Expressed-Value) + Symbol Denoted-Value = Ref(Expressed-Value) Code for expressed values: (define-datatype Expressed-Value expval? (number->expressed (number number?)) (procval->expressed (procval procval?)) (object->expressed (object object?)) (list->expressed (list (list-of expval?))) (symbol->expressed (symbol symbol?)) ) ------------------------------------------ 2. programs ------------------------------------------ EVAL-PROGRAM (deftype eval-program (-> (program) datum)) (define eval-program (lambda (pgm) (cases program pgm (a-program (c-decls body) (elaborate-class-decls! c-decls) (expressed->printable (eval-expression body (init-env))))))) ------------------------------------------ why do we need the call to elaborate-class-decls!? 3. expressions ------------------------------------------ EVAL-EXPRESSION (deftype eval-expression (-> (expression environment) Expressed-Value)) (define eval-expression (lambda (exp env) (cases expression exp (quote-exp (sym) (symbol->expressed sym)) ;; ... (new-object-exp (class-name rands) (method-app-exp (obj-exp method-name rands) (super-call-exp (method-name rands) ))) ------------------------------------------ What other procedures has to be written to make these work? What are these supposed to do? What are their types? C. four implementations (5.4) 1. a simple implementation (5.4.1) a. elaborating class declarations ------------------------------------------ A SIMPLE IMPLEMENTATION (5.4.1) (deftype the-class-env (list-of class-decl)) (define the-class-env '()) (deftype elaborate-class-decls! (-> ((list-of class-decl)) void)) (define elaborate-class-decls! (lambda (c-decls) ------------------------------------------ What should lookup-class do? b. objects ------------------------------------------ REPRESENTING OBJECTS (define-datatype object object? (an-object ------------------------------------------ How would you write object->class-name?? Given this, how would we build an object? ------------------------------------------ (deftype new-object (-> (symbol) object)) (define new-object (lambda (class-name) (an-object ------------------------------------------ What should class-decl->super-name do? how would you write it? c. find-method-and-apply ------------------------------------------ (deftype find-method-and-apply (-> (symbol symbol object (list-of Expressed-Value)) Expressed-Value)) (define find-method-and-apply (lambda (m-name host-name self args) ------------------------------------------ Q: What is host-name? What is host-name? ------------------------------------------ APPLY-METHOD (deftype apply-method (-> (method-decl symbol object (list-of Expressed-Value)) Expressed-Value)) (define apply-method (lambda (m-decl host-name self args) ------------------------------------------ What's the difference between this and find-method-and-apply? What progress have we made? What information do we need from the method declaration to execute it? What environment bindings do we need for the method execution? How do %super and self get out? ------------------------------------------ GETTING THE FIELDS IN THE ENVIRONMENT (deftype build-field-env (-> ((list-of part)) environment)) (define build-field-env (lambda (parts) ------------------------------------------ What kind of recursion is this? Why do we have to recur over a list of parts? Where do we start this recursion? ------------------------------------------ (deftype view-object-as (-> ((list-of part) symbol) (list-of part))) (define view-object-as (lambda (parts class-name) ------------------------------------------ Why does this work? 2. flat objects (5.4.2) a. objects ------------------------------------------ FLAT OBJECTS (5.4.2) New representation: (define-datatype object object? (an-object (class-name symbol?) (fields vector?))) Layout example (c3 < c2 < c1): -c1-- c2 -c3-- x y y x z [an-object | c3 | *-]-> [ | | | | ] ------------------------------------------ If c3 had a subclass, where would its fields appear? Do the fields of class c1 appear in the same index positions in objects in all of its subclasses? So how does searching work for variable names? ------------------------------------------ NEW-OBJECT (deftype new-object (-> (symbol) object)) (define new-object (lambda (class-name) (an-object class-name (make-vector (roll-up-field-length class-name) (number->expressed 0))))) (deftype roll-up-field-length (-> (symbol) number)) (define roll-up-field-length (lambda (class-name) (if (eqv? class-name 'object) 0 (+ (roll-up-field-length (class-name->super-name class-name)) (length (class-name->field-ids class-name)))))) ------------------------------------------ b. classes c. methods ------------------------------------------ APPLY-METHOD (deftype apply-method (-> (method-decl symbol object (list-of Expressed-Value)) Expressed-Value)) (define apply-method (lambda (m-decl host-name self args) (let ((ids (method-decl->ids m-decl)) (body (method-decl->body m-decl)) (super-name (class-name->super-name host-name)) (field-ids (fields (eval-expression body (extend-env (cons '%super (cons 'self ids)) (cons (symbol->expressed super-name) (cons (object->expressed self) args)) ------------------------------------------ ------------------------------------------ ROLL-UP-FIELD-IDS (deftype roll-up-field-ids (-> (symbol) (list-of symbol))) (define roll-up-field-ids (lambda (class-name) ------------------------------------------ What's the purpose of this procedure? What are we recursing over here? When do we search the chain of superclasses? 3. moving the work to class-declaration time (5.4.3) a. classes ------------------------------------------ CLASSES (define-datatype class class? (a-class (class-name symbol?) (super-name symbol?) (field-length integer?) (field-ids (list-of symbol?)) (methods method-environment?))) (define method-environment? (list-of method?)) ------------------------------------------ What should the field "methods" hold? When do we need to build classes? ------------------------------------------ ELABORATE-CLASS-DECLS! (deftype the-class-env (list-of class)) (define the-class-env '()) ;; ... (deftype elaborate-class-decls! (-> ((list-of class-decl)) void)) (define elaborate-class-decls! (lambda (c-decls) (initialize-class-env!) (for-each elaborate-class-decl! c-decls))) (deftype elaborate-class-decl! (-> (class-decl) void)) (define elaborate-class-decl! (lambda (c-decl) (let ((super-name (class-decl->super-name c-decl))) (let ((field-ids (append (class-name->field-ids super-name) (class-decl->field-ids c-decl)))) (add-to-class-env! (a-class (class-decl->class-name c-decl) super-name (length field-ids) field-ids (roll-up-method-decls c-decl super-name field-ids))))))) ------------------------------------------ What does this say about the order in which classes must be declared in a program? b. methods ------------------------------------------ METHODS (define-datatype method method? (a-method (method-decl method-decl?) (super-name symbol?) (field-ids (list-of symbol?)))) (deftype roll-up-method-decls (-> (class-decl symbol (list-of symbol)) (list-of method))) (define roll-up-method-decls (lambda (c-decl super-name field-ids) ------------------------------------------ What is this procedure supposed to be doing? What information could we use to produce a list of methods? ------------------------------------------ FIND-METHOD-AND-APPLY (deftype find-method-and-apply (-> (symbol symbol object (list-of Expressed-Value)) Expressed-Value)) (define find-method-and-apply (lambda (m-name host-name self args) (let loop ((host-name host-name)) (if (eqv? host-name 'object) (eopl:error 'find-method-and-apply "No method for name ~s" m-name) ------------------------------------------ ------------------------------------------ APPLY-METHOD (deftype apply-method (-> (method symbol object (list-of Expressed-Value)) Expressed-Value)) (define apply-method (lambda (method host-name self args) (let ((ids (method->ids method)) (body (method->body method)) (super-name (method->super-name method)) (field-ids (method->field-ids method)) (fields (object->fields self))) (eval-expression body (extend-env (cons '%super (cons 'self ids)) (cons (symbol->expressed super-name) (cons (object->expressed self) args)) (extend-env-refs field-ids fields (empty-env))))))) ------------------------------------------ How is this better in terms of getting the list of field identifiers? Is the host-name argument used in apply-method? c. objects ------------------------------------------ OBJECTS Representation is unchanged. (deftype new-object (-> (symbol) object)) (define new-object (lambda (class-name) (an-object class-name (make-vector (number->expressed 0))))) ------------------------------------------ How can we find out how long the vector should be? 4. flat method environments (5.4.4) a. classes ------------------------------------------ CLASSES (define-datatype class class? (a-class (class-name symbol?) (super-name symbol?) (field-length integer?) (field-ids (list-of symbol?)) (methods method-environment?))) Same as before except methods includes all methods reachable for objects of this class. ------------------------------------------ How to make that happen? ------------------------------------------ (deftype roll-up-method-decls (-> (class-decl symbol (list-of symbol)) (list-of method))) (define roll-up-method-decls (lambda (c-decl super-name field-ids) (merge-methods (class-name->methods super-name) (map (lambda (m-decl) (a-method m-decl super-name field-ids)) (class-decl->method-decls c-decl))))) ------------------------------------------ what should merge-methods do? b. methods What searching does this avoid? ------------------------------------------ FIND-METHOD-AND-APPLY (deftype find-method-and-apply (-> (symbol symbol object (list-of Expressed-Value)) Expressed-Value)) (define find-method-and-apply (lambda (m-name host-name self args) (let ((declared-methods (class-name->methods host-name))) (if (has-method? m-name declared-methods) (let ((meth (lookup-method m-name declared-methods))) (apply-method meth host-name self args)) (eopl:error 'find-method-and-apply "No method for name ~s" m-name))))) ------------------------------------------ D. variations 1. fields Can classes see fields declared in superclasses? What's the privacy of fields in this interpreter? What we have to do to have static, or class, variables? 2. methods How could we implement overloading? 3. classes Do we really need classes? What kind of inheritance does the defined language have? What kinds of problems might be caused by multiple inheritance? 4. objects Could we implement tuples of objects? How? Could we define methods on tuples of objects? How?