Com S 342 meeting -*- Outline -*- * Objects and Classes (7.1) ** ideas, terms *** simple picture: state, methods ------------------------------------------ OBJECTS AND CLASSES (7.1) A STACK OBJECT ______________________ | top-index [ 2 ] | | | | _________ push! | | | | | |_______| | | | 3 | pop! | |_______| | | | 4 | | | |_______| top | | 2 | | | stk |_______| | | | |______________________| state = instance variables methods (operations) = code that responds to messages instance = object ------------------------------------------ Q: What's the C++ jargon for "instance variable"? For method? data member, (virtual) function member Q: What's an object like that we've already seen? a closure: has code (methods), and environment (instance vars) *** classes ------------------------------------------ TWO OBJECTS OF THE SAME CLASS ___________ ___________ | | | | | top-index | | top-index | | [ 1 ] push! | [ 2 ] push! | | | | | _____ | | _____ | | |___| pop! | |___| pop! | |___| | | |_3_| | | |_2_| | | |_4_| | | stk|_7_| top | stk|_2_| top | | | | |___________| |___________| def: an *instance variable* is private to each def: a *class variable* is shared by def: *class* is used to mean: ------------------------------------------ ... object Point out that each has its own copy of instance variables. ... all instances of a class You can also have variables shared by all objects, those are called class variables Q: What's the C++ jargon for class variable? static data member ... - a set of instances with same internal structure (vars, methods) - the code that defines this a structure - an object that, at run-time can be used to produce instances (the run-time representative of the class code) A class is thus like a factory: it produces objects. What's that like? a function (that will be our semantics until 7.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 ------------------------------------------ Q: What does the message do? asks if the object will do this Contrast message passing with function calls, or Ada-like ADTs. ... ADT Several classes may implement the same ADT, may all coexist in a program! This is calling a virtual function in C++. Q: What's all this good for? We're going to focus on the semantics, not the programming techniques. ** syntax ------------------------------------------ NEW SYNTAX FOR OBJECTS AND CLASSES Concrete syntax: ::= | | := | := | method | $ () | simpleinstance | simpleclass ::= & ::= && ::= ( ) | ( ) EXAMPLE ------------------------------------------ Recall that ::= ( ) | ( ) ::= {,}* describe each form. ... define CellClass = simpleclass () % no class variables (value) % instance variable named value (initialize = method() &value := 0; getVal = method() &value; setVal = method(x) &value := x) 0; % no class variable initialization simpleinstance CellClass; ------------------------------------------ EXAMPLE WITH CLASS VARIABLES --> define CellWithStatsClass = simpleclass (callsMade) % class variable (value) % instance variable (initialize = method() &value := 0; getVal = method() begin &&callsMade := add1(&&callsMade); &value end; setVal = method(x) begin &&callsMade := add1(&&callsMade); &value := x end; numCalls = method() &&callsMade ) &&callsMade := 0; --> define o = simpleinstance CellWithStatsClass; --> $setVal(o, 3); --> $getVal(o); ------------------------------------------ continue this transcript... --> $numCalls(o); --> define o2 = simpleinstance CellWithStatsClass; --> $numCalls(o2); etc. ** initialization Q: How does a CellWithStatsClass object get initalized? by calling setVal Q: is that safe? no How is this handled in C++? We'll make a method called "initialize" that is called when an object is created. Like the C++ default constructor ** interpreter *** abstract syntax ------------------------------------------ NEW ABSTRACT SYNTAX (define-record i-varref (var)) (define-record c-varref (var)) (define-record i-varassign (var exp)) (define-record c-varassign (var exp)) (define-record meth-app (name rands)) (define-record method (formals body)) (define-record new-simpleinst (class-exp)) (define-record new-simpleclass (c-vars i-vars methdecls init-exp)) ------------------------------------------ c-vars and i-vars arre lists of symbols methdecls is a list of methods *** domains Warning to students: we'll make some slight corrections that aren't in the older texts... ------------------------------------------ DOMAINS FOR SECTION 7.1 Environment = -> Denoted-Value Denoted-Value = Cell(Expressed-Value) Expressed-Value = Number + Procedure Procedure = prim-proc + closure Instance = Class = NEW DATA STRUCTURES (define-record instance (define-record class ------------------------------------------ ... + Instance + Class + Open-Method ... Class x Vector(Denoted-Value) ... {}* x Vector(Denoted-Value) x {}* x Method-Environment where Q: Does the class variable environment need nesting? depends, but for us it doesn't. so we represent it using just list of symbols and vector of cells ... (define-record instance (class i-vals)) ... (define-record class (c-vars c-vals i-vars m-env)) i-vals is a vector of cells containing expressed values i-vars and c-vars is a list of symbols c-vals is a vector of cells containing expressed values But, for use in inheritance section, the vector of cells is stored in reverse (!) order from the names. ------------------------------------------ EXPRESSED VALUE PROCEDURES instance? : (-> (Expressed-Value) boolean) make-instance : (-> (Expressed-Value (vector Denoted-Value)) Expressed-Value) instance->class : (-> (Expressed-Value) Expressed-Value) instance->i-vals : (-> (Expressed-Value) (vector Denoted-Value)) class? : (-> (Expressed-Value) boolean) make-class : (-> ((list symbol) (vector Denoted-Value) (list symbol) Method-Environment) Expressed-Value) class->c-vars : (-> (Expressed-Value) (list symbol)) class->c-vals : (-> (Expressed-Value) (vector Denoted-Value)) class->i-vars : (-> (Expressed-Value) (list symbol)) class->m-env : (-> (Expressed-Value) Method-Environment) ------------------------------------------ ------------------------------------------ MORE EXPRESSED VALUE PROCEDURES open-method->expressed : (-> ((-> ((-> () Expressed-Value)) (-> ((list Expressed-Value)) Expressed-Value))) Expressed-Value) expressed->open-method : (-> (Expressed-Value) (-> ((-> () Expressed-Value)) (-> ((list Expressed-Value)) Expressed-Value))) number->expressed : (-> (number) Expressed-Value) expressed->number : (-> (Expressed-Value) number) procedure->expressed : (-> (Procedure) Expressed-Value) expressed->procedure : (-> (Expressed-Value) Procedure) list->expressed : (-> ((list Expressed-Value)) Expressed-Value) expressed->list : (-> (Expressed-Value) (list Expressed-Value)) void->expressed : (-> (void) Expressed-Value) denoted->expressed : (-> (Denoted-Value) Expressed-Value) expressed->denoted : (-> (Expressed-Value) Denoted-Value) ------------------------------------------ ------------------------------------------ INSTANCE AND CLASS VARIABLE PROCS (7.1.4) (define lookup ;; TYPE: (-> (symbol (list symbol) ;; (vector Denoted-Value)) ;; Expressed-Value) (lambda (var vars vals) (cell-ref (cell-lookup var vars vals)))) (define assign! ;; name changed ;; TYPE: (-> (symbol Expressed-Value ;; (list symbol) ;; (vector Denoted-Value)) ;; void) (lambda (var value vars vals) (cell-set! (cell-lookup var vars vals) value))) ------------------------------------------ Q: How would we have written lookup in chapter 6? (compose cell-ref cell-lookup) ------------------------------------------ MORE INSTANCE AND CLASS VARIABLE PROCS (define cell-lookup ;; TYPE: (-> (symbol (list symbol) ;; (vector Denoted-Value)) ;; Denoted-Value) (lambda (var vars vals) (letrec ((loop ; TYPE:(-> ((list symbol) number) ; Denoted-Value) (lambda (vars c) (cond ((null? vars) (error "Unassigned variable:" var)) ((eq? (car vars) var) (vector-ref vals c)) (else (loop (cdr vars) (- c 1))))))) (loop vars (- (length vars) 1))))) ------------------------------------------ For methods, use the the following new environment ADT. ------------------------------------------ METHOD ENVIRONMENT ADT the-empty-method-env : Method-Environment extend-method-env : (-> ((list symbol) (list Method) Method-Environment) Method-Environment) apply-method-env : (-> (Method-Environment symbol) Method) defined-in-method-env? : (-> (Method-Environment symbol) boolean) ------------------------------------------ just like environment with name changes This is a change from the book. ------------------------------------------ DOMAINS FOR METHODS Method-Environment = -> Method Open-Method = Class-Thunk -> Method Class-Thunk = () -> Class Method = {Expressed-Value}* -> Expressed-Value PROCEDURES FOR ACCESSING METHODS (define meth-call ;; TYPE: (-> (symbol Class ;; (list Expressed-Value)) ;; Expressed-Value) (lambda (name class args) (let ((method (meth-lookup name class))) (method args)))) (define meth-lookup ;; TYPE: (-> (symbol Class) Method) (lambda (name class) (apply-method-env (class->m-env class) name))) ------------------------------------------ Q: What's the parameter mechanism used to call methods? by value Q: How can you tell? Q: Would this allow others? no Where does the class thunk get filled in? we'll see that below in the class creation section (may want to do that now...) *** evaluation of expressions ------------------------------------------ EVAL-EXP FOR SECTION 7.1 INSTANCE AND CLASS VARIABLES (define eval-exp ;; TYPE: (-> (parsed-exp Environment ;; (maybe Class) ;; (maybe Instance)) ;; Expressed-Value) (lambda (exp env class inst) (variant-case exp (i-varref (var) (c-varref (var) ;; for you to do (i-varassign (var exp) (c-varassign (var exp) ;; for you ------------------------------------------ ... (lookup var (class->i-vars (something->value class)) (instance->i-vals (something->value inst)))) ... (lookup var (class->c-vars (something->value class)) (class->c-vals (something->value class)))) ... (let ((value (eval-exp exp env class inst))) (void->expressed (assign! var value (class->i-vars (something->value class)) (instance->i-vals (something->value inst)))))) ... (let ((value (eval-exp exp env class inst)) (c-vals (class->c-vals (something->value class)))) (void->expressed (assign! var value (class->c-vars (something->value class)) c-vals)))) ------------------------------------------ THE MAYBE ADT maybe? : (-> (datum) boolean) make-something : (-> (T) (maybe T)) make-nothing : (-> () (maybe T)) maybe-something?: (-> ((maybe T)) boolean) maybe-nothing? : (-> ((maybe T)) boolean) something->value : (-> ((maybe T)) T) maybe-test : (-> ((maybe T) (-> (T) U) (-> () U)) U) ------------------------------------------ ------------------------------------------ METHODS (define eval-exp (lambda (exp env class inst) (variant-case exp ;; ... (method (formals body) (meth-app (name rands) ------------------------------------------ ... (let ((new-formals (cons 'self formals))) (open-method->expressed (lambda (class-thunk) (lambda (args) (eval-exp body (extend-env new-formals (map expressed->denoted args) env) (make-something (class-thunk)) (make-something (car args)))))))) ... (let ((args (map (lambda (rand) (eval-exp rand env class inst)) rands))) (meth-call name (instance->class (car args)) args))) ------------------------------------------ INSTANCE CREATION (define eval-exp (lambda (exp env class inst) (variant-case exp ;; ... ------------------------------------------ (new-simpleinst (class-exp) (let ((inst-class (eval-exp class-exp env class inst))) (let ((new-inst (make-instance inst-class (make-vals (class->i-vars inst-class))))) (ignore (meth-call 'initialize inst-class (list new-inst))) new-inst))) ------------------------------------------ AUXILIARY FUNCTIONS FOR INSTANCE CREATION (define make-vals ;; TYPE: (-> ((list symbol)) ;; (vector Denoted-Value)) (lambda (vars) (list->vector (map (lambda (x) (make-cell (number->expressed 0))) vars)))) ------------------------------------------ ------------------------------------------ CLASS CREATION (define eval-exp (lambda (exp env class inst) (variant-case exp ;; ... ------------------------------------------ ... (new-simpleclass (c-vars i-vars methdecls init-exp) (let ((open-methods (map (lambda (decl) (expressed->open-method (eval-exp (decl->exp decl) env class inst))) methdecls))) (letrec ((new-class (make-class c-vars (make-vals c-vars) i-vars (extend-method-env (map decl->var methdecls) (map (lambda (open-meth) (open-meth (lambda () new-class))) open-methods) init-meth-env)))) (ignore (eval-exp init-exp env (make-something new-class) (make-nothing))) new-class))) Q: Can methods be recursive? How does that work? ------------------------------------------ INITIAL METHOD ENVIRONMENT (define init-meth-env ; corrected ;; TYPE: Method-Environment (extend-method-env '(initialize) (list (lambda (args) (void->expressed (displayln "Not initialized")))) the-empty-method-env)) ------------------------------------------ Q: What does this do? gives an error when used, so must be overridden