Com S 342 meeting -*- Outline -*- * inheritance (7.2) bring: copies of fig7.2.6.C to class ** varieties ------------------------------------------ INHERITANCE (7.2) idea: similar kinds of objects should share Techniques: delegation inheritance Varieties: single multiple ------------------------------------------ ... common methods and variables ... delegation = dynamic code sharing objects pass messages (and self pointer) along to other objects to handle message (The book is wrong here in that it doesn't talk about getting the self pointer passed along...) ... inheritance = static code sharing each class has one or more parent classes (superclasses) from which it inherits code and variables ... single = each class has 1 parent ... multiple = each class may have any number of parents Q: If a class has two parents, each with method M, what is done? Q: What if both parents define the same instance variable? it's complex... ** syntax ------------------------------------------ CONCRETE SYNTAX ::= ... | $ () | simpleinstance | class , | $ ::= & ::= && ::= ( ) | ( ) ::= (super {, }*) ------------------------------------------ the first expression, before the comma, is the superclass use "baseobject" when no parent is desired. ------------------------------------------ EXAMPLE define CellClass = class baseobject, % superclass () % no class variables (value) % instance variable (initialize = method() &value := 0; getVal = method() &value; setVal = method(x) &value := x) 0; % no class var initialization define DebugCellClass = class CellClass, () % no class variables () % no instance variables (setVal = method(x) begin printchar(83); space(); %83=S print(x); newline(); $setVal(super,x) end; getVal = method() begin printchar(71); space(); %71=G let v = $getVal(super) in begin print(v); newline(); v end end ) 0; ------------------------------------------ note use of baseobject in CellClass, and super note that initialize is inherited without change, getVal and setVal are overriddern ------------------------------------------ RUNNING IT --> define myCell = simpleinstance CellClass; --> define myDCell = simpleinstance DebugCellClass; --> $getVal(myCell); --> $getVal(myDCell); --> $setVal(myDCell, 3); --> +($getVal(myDCell), $getVal(myDCell)); ------------------------------------------ ... 0 ... G 0 0 ... S 3 ... G 3 G 3 6 Do some more if needed. Might point out that this is like virtual functions in C++, the "default" in C++ is static overloading. ** semantics *** Conceptual domains and data structures ------------------------------------------ SEMANTICS Domains: Environment = -> Denoted-Value Denoted-Value = Cell(Expressed-Value) Expressed-Value = Number + Procedure + List(Expressed-Value) + Void + Instance + Class + Open-Method Procedure = prim-proc + closure Instance = Class x Vector(Denoted-Value) Class = Open-Method = Class-Thunk -> Method Class-Thunk = () -> Class Method = {Expressed-Value}* -> Expressed-Value Method-Environment = -> Method New data structures for expressed values: (define-record class ------------------------------------------ ... Class = Maybe(Class) x {}* x Vector(Denoted-Value) x {}* x Method-Environment the use of Maybe is needed to break what would otherwise be an infinite recursion. ... (parent c-vars c-vals i-vars m-env)) Q: What has to happen when making up the class vars for a class exp? evaluate the parent class expression add the list of class vars to those inherited from parent similarly with the instance variables extend the parent's method environment with the open methods declared Q: What has to happen when doing a method call that uses super? do meth-call but use (class->parent class) instead of class See Fig. 7.2.4 for details on how this is implemented. *** super method application ------------------------------------------ EVAL-EXP FOR SECTION 7.2 SUPER METHOD APPLICATION (define eval-exp ;; TYPE: (-> (parsed-exp Environment ;; (maybe Class) ;; (maybe Instance)) ;; Expressed-Value) (lambda (exp env class inst) (variant-case exp ;; ... (super-meth-app (name rands) ------------------------------------------ ... (let ((args ; TYPE: (list Expressed-Value) (map (lambda (x) (eval-exp x env class inst)) rands))) (meth-call name (something->value (class->parent (something->value class))) (cons (something->value inst) args)))) ------------------------------------------ EVAL-EXP FOR SECTION 7.2 NEW CLASS EXPRESSION (define eval-exp (lambda (exp env class inst) (variant-case exp ; ... (new-class (parent-exp c-vars i-vars methdecls init-exp) ... (let ((parent-class (open-methods (map (lambda (decl) (expressed->open-method (eval-exp (decl->exp decl) env class inst)) methdecls))) ------------------------------------------ ... (let ((parent-class (eval-exp parent-exp env ; <--- write in this class inst)) ; <--- (map (lambda (decl) (expressed->open-method (eval-exp (decl->exp decl) env class inst)) methdecls))) (let ((new-c-vars (append c-vars (class->c-vars parent-class))) (new-i-vars (append i-vars (class->i-vars parent-class))) (new-c-vals ; NEW! (make-shared-c-vals (class->c-vals parent-class) c-vars))) ------------------------------------------ ;; NEW CLASS CONTINUED (letrec ((new-class (make-class (make-something parent-class) new-c-vars new-c-vals new-i-vars (extend-method-env (map decl->var methdecls) (map (lambda (open-method) (open-method (lambda () new-class))) open-methods) (ignore (eval-exp init-exp env (make-something new-class) (make-nothing) new-class)))) ------------------------------------------ ... (class->m-env parent-class))))) ------------------------------------------ AUXILIARY FUNCTIONS for 7.2.4 (define make-shared-c-vals ;; TYPE: (-> ((vector Denoted-Value) ;; (list symbol)) ;; (vector Denoted-Value)) (lambda (parent-c-vals c-vars) (list->vector (append (vector->list parent-c-vals) (map (lambda (x) (expressed->denoted (number->expressed 0))) c-vars))))) (define make-vals ;; TYPE: (-> ((list symbol)) ;; (vector Denoted-Value)) (lambda (vars) (list->vector (map (lambda (x) (expressed->denoted (number->expressed 0))) vars)))) ------------------------------------------ *** some examples ------------------------------------------ MESSAGE PASSING EXAMPLE define Cclass = class baseobject, () () (initialize = method() noop; m1 = method () $m2(self); m2 = method () 3 ) 0; define Dclass = class Cclass, () () (m2 = method () 4 ) 0; define aD = simpleinstance Dclass; --> $m1(aD); ------------------------------------------ Q: what is the result of $m1(aD) ? returns 4 Discuss how, draw picture Q: What if we added another method to D... m3 = method() $m2(super) and then ran $m3(aD) ? Q: What if m2's body was "$m2(self)" instead? ------------------------------------------ MESSAGE PASSING EXAMPLE WITH SUPER define C2class = class baseobject, () () (initialize = method() noop; m1 = method () $m2(self); m2 = method () 3; m3 = method () 14 ) 0; define D2class = class C2class, () () (m2 = method () $m3(super); m3 = method () 5 ) 0; %%% FOR YOU TO DO %%% --> $m1(simpleinstance C2class); --> $m1(simpleinstance D2class); ------------------------------------------ Q: What is the result (if any) of $m1(simpleinstance C2class) ? 3 Q: What is the result (if any) of $m1(simpleinstance D2class) ? 14 If you got 5 you don't see how super works. ** scope issues ------------------------------------------ LEXICAL SCOPE vs. INSTANCE VARIABLES ;;; Figure 7.2.5 : page 230 define aclass = class baseobject, (cv) (iv) () &&cv := 7; let x = 3; cv = 4; iv = 5 in let bclass = class aclass, () () (initialize = method () &iv := +(x, &&cv); getiv = method () &iv ) 0 in let b = simpleinstance bclass in list($getiv(b), x, cv, iv); ------------------------------------------ Q: What does this return? (10 3 4 5) Q: How would you explain the scoping? ------------------------------------------ fig 7.2.6 STATIC vs. DYNAMIC INHERITANCE OF INSTANCE VARIABLES define aclass = class baseobject, (cv) (iv) (initialize = method () &iv := 8; getcv = method () &&cv; getiv = method () &iv) &&cv := 6; define bclass = class aclass, (cv) (iv) (initialize = method () begin $initialize(super); &iv := 9 end) &&cv := 7; define x = simpleinstance bclass; define c = $getcv(x); define i = $getiv(x); ------------------------------------------ Q: What is the value of c? i? what could they be? ------------------------------------------ TERMS static = references to class and instance vars resolved in environment of the dynamic = references resolved in environment of the ------------------------------------------ static = ... class to which the current method was declared dynamic = ... dynamic class of the current instance A language could also disallow this situation, as does Smalltalk V and Java. According to the book: C++ is static, Smalltalk is dynamic (Smalltalk-80?) That is, in C++, c=6 and i=8 Q: What does our interpreter do? How can you tell? look at what i-varref and c-varref do, it's based on the current class (the class parameter to eval-exp) How is the current class set? statically, from the class-thunk in the method case. How could we change it to be dynamic? use (instance->class inst) instead of (class-thunk) in the i-varref and/or c-varref cases.