I. Smalltalk A. Message expression syntax 1. Basic expressions a. Identifiers ------------------------------------------ SMALLTALK: IDENTIFIERS Identifier Conventions Upper case: ClassNames lower case: instancevar Pseudo Variables self, super, smalltalk Special Names Instances: true, false, nil Classes: True, False, UndefinedObject Case matters: True (the class) vs. true (the instance) ------------------------------------------ b. Literals ------------------------------------------ LITERALS 3 30.45 $a "the character a" 'a string, don''t laugh!' #aSymbol #aSymbol:composed:ofKeywords: #* "also a symbol" #(1 2 3) "an array constant" #(foo bar 'and me') ------------------------------------------ 2. messages ------------------------------------------ KINDS OF MESSAGES Unary messages: 1 negated theta sin Pen new home green Binary messages: 3 + 4 5 - 4 * 2 (sum / count) * (reserve amount) Keyword messages: 3 max: 2 anArray at: 2 put: 3 (anArray at: 2) at: 3 ------------------------------------------ 3. Parsing ------------------------------------------ PRECEDENCE unary highest (most tight) binary keyword lowest (least tight) ASSOCITIVITY IS LEFT TO RIGHT 4 - 5 * 3 is (4 - 5) * 3 2 * theta sin is 2 * (theta sin) frame width: otherFrame width * 2 is frame width: ((otherFrame width) * 2) FOR YOU TO DO Parenthesize the following: foo at: 2 negated put: 4 + 3 * 2 negated ------------------------------------------ B. Blocks (closures) 1. statically scoped ------------------------------------------ BLOCKS Block = Examples: [ i print ] [ k <- k+1. k print. k ] [ :x :y | (x+y) print ] FOR YOU TO DO What is (a) printed and (b) returned by: [ :y | (y + 2) print. y ] value: 4 ------------------------------------------ C. Control Structures ------------------------------------------ CONTROL STRUCTURES (x > y) ifTrue: [x print] ifFalse: [y print] (x > y) and: [y > z] [i > 0] whileTrue: [i print. i <- i - 1] 3 timesRepeat: [4 print] ((1 to: 5) step: 2) do: [:i | i print] ------------------------------------------ ------------------------------------------ FOR YOU TO DO 1. Write a statement that prints the numbers from i to 10 in ascending order. 2. Write a statement that prints all the numbers in a set s that are greater than 3 s do: ------------------------------------------ D. Classes 1. Stack example ------------------------------------------ MAKING A CLASS > Object addSubClass: #Stack \ instanceVariableNames: 'elems' Object > Stack display Class Name: Stack SuperClass: Object Instance Variables: elems Subclasses: Stack TO ADD METHODS > Stack addMethod ------------------------------------------ ------------------------------------------ "methods for Stack" new elems <- List new push: anElement elems addFirst: anElement pop elems removeFirst isEmpty ^ elems isEmpty top ^ elems first printString "would be 'contents' in ST-80" | s | s <- 'Stack ('. elems do: [ :e | s <- s , ' ', e printString]. ^ s , ' )' ------------------------------------------ 2. Exercise ------------------------------------------ FOR YOU TO DO Complete the following class for a counter > Object addSubClass: #Counter \ instanceVariableNames: ' ' "methods for Counter" new increment value printString ------------------------------------------ E. object creation in little smalltalk ------------------------------------------ OBJECT CREATION IN LITTLE SMALLTALK How Stack new executes 1. send the "new" message to the class object "Stack" This: - creates - sets instance variables to 2. The new instance is sent the message ------------------------------------------ F. Semantics of variables, assignment, and mutation 1. object identity ------------------------------------------ OBJECT IDENTITY objects have an identitity = state = EXAMPLE s <- Stack new. s push: 1. s push: (Stack new push: 2). s push: s ------------------------------------------ 2. mutable vs. immutable ------------------------------------------ MUTABLE vs. IMMUTABLE OBJECTS def: an object is *mutable* if otherwise an object is *immutable* ------------------------------------------ are integers mutable in smalltalk? 3. variables and assigment ------------------------------------------ VARIABLES AND ASSIGNMENT def: a variable in Smalltalk is EXAMPLE p1 <- p2 like Pascal: var p1, p2: Point; { a pointer!} new(p); new(p2); p1 := p2. or C: typedef PointStruct * Point; Point p1, p2; ... p1 = p2; ------------------------------------------ Does an assigment copy the object in Smalltalk? What kind of value is in a Smalltalk variable? II. Inheritance A. Hierarchy of classes B. Example: Adding size to stacks ------------------------------------------ SIZED STACK > Stack addSubClass: #SizedStack \ instanceVariableNames: 'size' "methods for SizedStack" new ------------------------------------------ 1. Inheriting data 2. Inheriting operations ------------------------------------------ STEPS IN MESSAGE SENDING let receiver = object that is sent message let static-class = class where code being executed is defined let rc = if receiver is not super, then receiver's (dynamic) class else if receiver is "super" then superclass of static-class 1. [fetch] look for method in class rc (a) if found: (b) if not found and rc is not Object: (c) if not found and rc is Object: 2. [execute] bind self to bind super to bind formals to allocate temporary vars (|temp|), execute the code of the method ------------------------------------------ a. semantic examples without super ------------------------------------------ MESSAGE PASSING EXAMPLE > Object addSubClass: #C \ instanceVariableNames: '' > C addSubClass: #D \ instanceVariableNames: '' "methods for class C" m1 ^self m2 m2 ^ #C "methods for class D" m2 ^ #D ------------------------------------------ what is the result of x <- D new. x m1 ? What if we added another method to D... m3 ^ super m2 and then ran x m3? What if m2's body was "^ self m2" instead? b. semantic examples with super ------------------------------------------ MESSAGE PASSING EXAMPLE WITH SUPER > Object addSubClass: #C \ instanceVariableNames: '' > C addSubClass: #D \ instanceVariableNames: '' "methods for class C" m1 ^ self m2 m2 ^ 'C' m3 ^ 'm3' "methods for class D, subclass of C" m2 ^ super m3 m3 ^ 'E' ------------------------------------------ What is the result (if any) of the expression "C new m1"? What is the result (if any) of the expression "(D new) m1"? C. Example: CachedStack ------------------------------------------ CACHED STACK > Stack addSubClass: #CachedStack \ instanceVariableNames: 'cache' "methods for CachedStack" ------------------------------------------ 1. How to define printString? Smalltalk's read-eval-print uses printString ------------------------------------------ INHERITING PRINT METHODS printString for CachedStack "following is bad style, but works" printString | s | s <- 'Stack ('. (cache notNil) ifTrue: [s <- s , ' ' , cache printString]. elems do: [ :e | s <- s , ' ' , e printString]. ^ s , ' )' problems with the above: - ------------------------------------------ 2. Inheriting printString by factoring out common parts ------------------------------------------ INHERITANCE BY FACTORING OUT COMMON PARTS "methods for Stack" printString ^ 'Stack(' , self printStringElements , ')' printStringElements | s | s <- ''. elems do: [ :e | s <- s , ' ' , e printString]. ^s FOR YOU TO DO Define whatever methods are *needed* to have printString work for CachedStack ------------------------------------------ D. exercise Can you write Gague, like Counter, but also has a decrement method? E. Design issue: Single vs. multiple inheritance ------------------------------------------ SINGLE VS. MULTIPLE INHERITANCE def: a language has *single inheritance* if each class has def: a language has *multiple inheritance* if each class may have Motivating problem: what if want SizedCachedStack? ------------------------------------------ III. OO programming tactics what ways of programming are enabled by the mechanisms of OO languages like Smalltalk? A. encapsulation (from objects) Is there a fundamental difference between data and operations? 1. making objects "intelligent" ------------------------------------------ 2 KINDS OF "GOD CLASS" Behavioral c1 <-get_x()- [ GOD ] -set_q()-> c4 / \ / \ get_y() set_result() / \ v v c2 c3 Data Structural c1 -get_x()-> [ GOD ] <-set_q()- c4 ^ ^ / \ get_y() set_result() / \ / \ c2 c3 ------------------------------------------ 2. composition vs. inheritance ------------------------------------------ COMPOSITION vs. INHERITANCE composition |-----------------| |-----------| | Rectangle |------->*| Point | |-----------------| |-----------| inheritance |-----------------| | Point | |-----------------| | | / \ |-----------------| |-----------| | Rectangle |-------->| Point | |-----------------| |-----------| ------------------------------------------ should Rectangle be represented by 2 points or should it be a subclass of Point? B. protocols and polymorphism (from message passing) 1. protocols, types, and behavior ------------------------------------------ PROTOCOLS, TYPES, and BEHAVIOR def: the protocol (interface) of an object is def: the behavioral protocol of an object is def: a type is def: S is a subtype of T if def: S is a behavioral subtype of T if ------------------------------------------ What should a type be? What would it mean for S to not be a subtype of T? What should a behavioral subtype be? What would it mean for S to not be a behavioral subtype of T, and still be a subtype of T? 2. subtype vs. inheritance What does subtyping have to do with inheritance? What do we know about these? ------------------------------------------ SUBTYPING VS. INHERITANCE | ===================|====================== class | | subclass | | type | | subtype | | behavioral subtype | | ------------------------------------------ ------------------------------------------ ORTHOGANALITY EXAMPLE IntSetType ^ IntSetClass | subtype | IntervalType IntervalClass ------------------------------------------ How does C++ handle this? Java? What can we do to make a subclass not be a behavioral subtype? 3. polymorphism ------------------------------------------ POLYMORPHISM def: code is *polymorphic* if e.g., displayAll: objList objList do: [ :o | o display ] ------------------------------------------ What's the language design tradeoff here? C. code reuse (from inheritance) 1. factoring behavior so relevant parts can be inherited ------------------------------------------ FROM INHERITANCE What benefits? 1. Factoring ------------------------------------------ 2. abstract classes ------------------------------------------ ABSTRACT CLASSES def: an abstract class is def: a deferred method is ------------------------------------------ 3. using message passing instead of tests in code ------------------------------------------ USE MESSAGE PASSING INSTEAD OF TESTS Boolean / \ True False "instance methods for True" ifTrue: b1 ifFalse: b2 ^ b1 value "instance methods for False" ifTrue: b1 ifFalse: b2 ^ b2 value ------------------------------------------ ------------------------------------------ FOR YOU TO DO Program: LISPList / \ Empty Cons methods implemented in LISPList: length (self isEmpty) ifTrue: [^0] ifFalse: [^ 1 + self tail length] deferred methods: head, tail, isEmpty Notes: (Empty new) head gives an error Cons has instance variables: hd,tl and method head:tail: to initialize ------------------------------------------ ------------------------------------------ ADTs vs. OO Programming Empty | Cons ====================|===================== head tail isEmpty ------------------------------------------ D. mutation (from assignment) 1. mutatator operations ------------------------------------------ FROM ASSIGNMENT: MUTATION > l <- List new. List ( ) > l add: 3 List ( 3 ) ------------------------------------------ what higher-level operations could we have on points, instead of just get_x, set_x, get_y, set_y? 2. aliasing ------------------------------------------ ALIASING def: x and y are aliases for an object if Uses of aliasing: ------------------------------------------ How can you use aliasing in a program? How can you prevent aliasing? ------------------------------------------ EXPOSING THE REP > Collection addSubClass: #Ticket \ instanceVariableNames: 'rep' "instance methods" new rep <- Set new initialize: aSet rep <- aSet What if a client does the following? > mySet <- Set new > ... > myTicket <- Ticket new initialize: mySet > mySet add: "is this ok?" ------------------------------------------ What could go wrong?