CS 342 Lecture -*- Outline -*- * Smalltalk ** Syntax see p. 277 *** function definitions and expressions same as chapter 1 integers built-in true, false represented by 1 and 0 *** symbols #aSymbol # like ' in LISP can compare symbols using = *** Classes Modules that implement abstract types (like a cluster in CLU) instead of rep have list of instance variable names in parens don't need any: () each method (operation) has instance variable names as locals differences in Point example ------------------------------- Smalltalk CLU (xCord yCord) (rep xCord yCord) (set xCord x) (set-xCord p x) xCord (xCord p) self p (define rotate () (define rotate (p) ... self...) ...p ...) ------------------------------- see table on page 272 for terminology ** in class exercise: write something like the Point cluster from the CLU chapter. Show how to use it. then write a null? function on lists, (can do this either as a global function or as a method of a subclass of List) write a copy function to make a copy of a list ** example, stacks *** Stack class recall class = description of objects (module that defines rep, ops) ---------------- (class Stack Object (elems) ; instance variables (like the rep) (define initStack () (begin (set elems (mkList)) self)) ; have to return created object (define push: (x) (add: elems x)) (define pop () (removeFirst elems)) (define top () (car elems)) (define isEmpty () (isEmpty elems)) (define print () ; useful for debugging (begin (print #Stack) (printAux self (first elems)))) (define printAux (e) (begin (while (notNil e) (begin (print e) (set e (next elems)))) self)) ) (define mkStack () (initStack (new Stack))) (set myStack (mkStack)) ---------------- Note on conventions: classes start with upper case letter, use Upper case letter to separte words in names each class C (with instances) defines initC (because no "super" in this smalltalk) initializes state of object for each class C, define a function mkC to create instances this is only way instances should be created (ensures they are initialized) instance of class C = object created using the template of class C think of class as factory for objects operations not really stored in each object (too much space) class object = run-time storage for operations also object where can send messages to create instances each object is an instance of some class the class object is the denotation of Stack... *** Sized Stack defin SizedStack by saying how it differs from Stack SizedStack is subclass of Stack, superclass of SizedStack is Stack inherits methods + instance variables (algorithms + data structures) ---------- (class SizedStack Stack (size) (define initSizedStack () (begin (initStack self) (set size 0) self)) (define size () size) (define push: (x) (begin (set size (+ 1 size)) (add: elems x))) (define pop () (begin (set size (- 1 size)) (removeFirst elems))) ) (define mkSizedStack () (initSizedStack (new SizedStack))) (set sStack (mkSizedStack)) ---------- Show the layout of storage in instances of SizedStack ** Message Passing (generic invocation, dynamic binding) and polymorphism select the operation from the object, call it => like procedure call using dynamic overloading *** message = operation name + arguments ______________________ ____________ | | | \ / | __ | | | \ / | | push: | \/ | __ | | | push: 4 | | | |__________| | pop \ \ \ | | | | | top | | |______________________| object ^ message ^ ------------------ (push: myStack 4) (print (top myStack)) (pop myStack) (push: sStack 2) ------------------ Syntax in real ST is "myStack push: 1." (watch out for my mistakes with this syntax...) *** implementation (in Smalltalk) *draw picture showing class link, class object, dispatch table ---------------- Steps in message sending: let receiver = object that is sent message let c = class of receiver 1. [fetch] look for method in class c found: go to step 2 not found: if c is Object give error, else let c = superclass of c goto 1. 2. [call] bind formals to actuals and execute the code of the method ---------------- *** Message Passing and binding times **** early (static) binding call bound to a module (DU) at compile time specific implementation of that module selected at link time e.g., in CLU (stack$push myStack 1) **** delayed (late, dynamic) binding call bound to implementation later than link time e.g., in Smalltalk (push: myStack 1) dispatch needed at run-time in general, e.g. can depend on input --------------- (define assignMyStack (b) (if b (set myStack (mkStack)) (set myStack (mkSizedStack)))) (push: myStack 4) --------------- *** When to use message passing (dynamic binding) in design? Office Automation example: (Cox) various containers: desktops, envelopes, mailboxes, filefolders each may contain many diff types of objects (memos, files..) mailbox displaySummary -- displays a summary menu of contents let each object in mailbox contain a "typeid" (tells type) need map from typeid to method for getting summary info if local to displaySummary (e.g., case stmt), then implementor must change it for new types ==> map should be global to displaySummary ways to represent global map: centralized (table-driven) distributed among the types (message passing) so message passing is way to allow addition of types without causing other changes inheritance allows broadcast of changes (and regularity)