03G-1 Everything is an Object Examining builtin classes All these are classes in Little Smalltalk: Object Class Method Block Boolean True False Run time type information Implementation of new Printing objects
03G-2 Learning Smalltalk The best way to learn Smalltalk is to study the definitions of the builtin classes. A file containing the implementation of any class may be produced by following the steps bellow: >F <- File new name: 'block.st' File >F open: 'w' File >Block fileOutOn: F Block >F close File >^D
03G-3 The Class Object root The class Object is the root of Little Smalltalk ’ s hierarchy. Every other class inherits from it, either directly or indirectly. The existence of a single root is useful to assure that some messages are understood by any object. The methods defined in the class Object may be: Used to define a common behaviour. These methods need not be overridden. Their implementation is based on other methods. Used to provide a default behaviour. These methods should be overridden by subclasses when appropriate. primitives Some methods are implemented by calling primitives. A primitive is a kind of external function. Abstract Class The class Object is an Abstract Class. Question: What is the superclass of Object ?
03G-4 Objects ’ Printability The method print provides a common behaviour. Its implementation is based on the method printString. Class Object nil Methods Object print self printString print The method printString provides a default behaviour. The default is returning the name of the receiver ’ s class. Methods Object printString ^self class printString The method class is implemented by a primitive. Methods Object class ^
03G-5 Equality Tests The method == returns true if the receiver and argument are the same object. It is implemented by a primitive. Methods Object == aValue ^ The method ~~ is based on ==. It needs not be overridden. Methods Object ~~ aValue ^ ( self == aValue ) not The method = returns true if the receiver and argument are objects with the same value. It must be overridden. Methods Object = aValue ^ self == aValue
03G-6 Collection ’ s Equality The class Collection overrides the method = Methods Collection = coll self do: [ :x | ( self occurrencesOf: x ) = ( coll occurrencesOf: x ) ifFalse: [ ^false ] ]. ^true The class Collection provides a default behaviour that is more appropriate for its subclasses, based on method do: We should override the method = in class Complex Class Complex Object r i Methods Complex = aComplex ^ r = aComplex realpart and: [ i = aComplex imagpart ] BUG if self coll
03G-7 Copying Objects The method shallowCopy returns a copy of the receiver. Methods Object shallowCopy | newObj | newObj <- self class new. ( 1 to: self basicSize ) do: [:i | newObj basicAt:i put: ( self basicAt:i ) ] ^newObj The method shallowCopy provides common behaviour, based on methods basicSize and basicAt:, which are implemented by primitives. The method deepCopy copies also all of the objects within the receiver, recursively. It must be overridden. The method copy may be either a shallow or a deep copy, depending upon what is appropriate for the receiver.
03G-8 Deep Copy in Array The class Array overrides the method deepCopy. Class Array IndexedCollection Methods Array deepCopy ^ self deepCopyFrom: 1 to: self size | deepCopyFrom: low to: high | newArray newlow newhigh | newlow <- low max: 1. newhigh <- high min: self size. newArray <- self class new: (0 max: newhigh - newlow + 1). ( newlow to: newhigh ) do: [ :i | newArray at: i - newlow + 1 put: ( self at: i ) copy ]. ^newArray
03G-9
03G-10 The Class Class In Smalltalk, everything is an object. Classes are part of Smalltalk, hence classes are objects. The class Class defines the attributes and methods that are common to any Smalltalk class. The class Class is not an Abstract Class. Every class in Little Smalltalk is an instance of Class. As any class, the class Class is a subclass of Object. As any class, the class Object is an instance of Class. Actually, the class Class is an instance of itself. Who was born earlier, the chicken or the egg?
03G-11 Class Attributes The attributes of any class are: a name a superclass a set of methods a set of instance variables the instance size Additionally, classes have behaviour, which is defined by the methods implemented in the class Class. The most important method is the one that makes the class able to generate new instances. When we send to a class the message new, it executes the method new defined in the class Class.
03G-12 The Method New The method new first creates a new instance and then sends to it the message new. Methods Class new | newObject | newObject <- self new: instanceSize. ^ self == Class ifTrue: [ newObject initialize ] ifFalse: [ newObject new ] | new: size ^ self > | initialize superClass <- Object. instanceSize <- 0. methods <- Dictionary new new ’ s implementation is buggy in several fundamental classes, such as: LongInteger, Interval, Collection and Char.
03G-13 Looking for Methods When we send a message to an object, we first look for the method in its class. If it is not found we look recursively in the superclasses, until it is found or we reach the root. Methods Object respondsTo: message self class upSuperclassChain: [ :c | ( c methodNamed: message ) notNil ifTrue: [ ^true ] ]. ^false Methods Class upSuperclassChain: aBlock aBlock value: self. superClass notNil ifTrue: [ superClass upSuperclassChain: aBlock ]
03G-14 Run-Time Type Information dynamically typed Since Smalltalk is dynamically typed it is useful to ask about the identity of the objects. The methods isMemberOf: and isKindOf: may be used for type checking. Methods Object isMemberOf: aClass ^self class == aClass | isKindOf: aClass self class upSuperclassChain: [ :c | ( c == aClass ) ifTrue: [ ^true ] ]. ^false
03G-15 Type Checking We could implement type checking for complex numbers. Class Complex Object r i Methods Complex realpart: aNumber ( aNumber isKindOf: Number ) ifTrue: [ r <- aNumber ] ifFalse: [ smalltalk error: 'realpart must be number.' ] | + aComplex ( aComplex isMemberOf: Complex ) ifTrue: [ ^Complex new realpart: r + aComplex realpart; imagpart: i + aComplex imagpart ] ifFalse: [ smalltalk error: 'operand must be complex.' ]
03G-16 Design Techniques design techniques The builtin classes of Little Smalltalk provide several examples of design techniques that are characteristic of Object Oriented Programming. Some of these techniques are: composite methods Providing additional functionality using composite methods, implemented over basic ones. Example: The class Block. abstract classes The use of abstract classes implementing the common behavior of its subclasses. Example: The classes Boolean, True and False. cooperation Implementing a functionality through cooperation between distinct classes. Example: The classes Block, Method and Context. Example: The classes List and Link.
03G-17 Composite Methods useful A class should provide to its clients all the functionality that may be useful, even if not absolutely necessary. extended The protocol of a class may be extended by the addition of composite methods, implemented over basic ones. little effort The implementation of these additional methods requires very little effort, but makes the class more powerful. The main advantages of composite methods are: abstract The interface of the class becomes more abstract. complete The protocol of the class becomes more complete. The class becomes more useful. The class becomes easier to use. reusability Composite methods improve reusability.
03G-18 The Class Block basic composite The basic method whileTrue: is used to implement the composite methods whileTrue and whileFalse: Class Block Object context argCount argLoc bytePointer Methods Block whileTrue: aBlock ( self value ) ifTrue: [ aBlock value. self whileTrue: aBlock ] | whileFalse: aBlock [ self value not ] whileTrue: aBlock | whileTrue self whileTrue: [] ]
03G-19 Abstract Classes generalization Abstract classes are normally derived by the generalization of its subclasses. common behavior They provide a common behavior for their subclasses. composite The methods implemented by an abstract class are normally composite. The basic methods should be provided by the subclasses. The main advantages of abstract classes are: Provide a common protocol for the subclasses. Avoid several implementations of the same methods. Allow new subclasses to be derived without having to reimplement all the functionality. reused The methods implemented in an abstract class are reused by its subclasses.
03G-20 The Class Boolean The class Boolean is an abstract class. Class Boolean Object Methods Boolean ifTrue: trueBlock ^self ifTrue: trueBlock ifFalse: [] | ifFalse: falseBlock ^self ifTrue: [] ifFalse: falseBlock | ifFalse: falseBlock ifTrue: trueBlock ^self ifTrue: trueBlock ifFalse: falseBlock | and: aBlock ^self ifTrue: aBlock ifFalse: [ false ] | or: aBlock ^self ifTrue: [ true ] ifFalse: aBlock ]
03G-21 The Class True The class True inherits the functionality of Boolean. Class True Boolean Methods True ifTrue: trueBlock ifFalse: falseBlock ^trueBlock value | not ^false | xor: aBoolean ^aBoolean not | printString ^'true' ]
03G-22 The Class False The class False inherits the functionality of Boolean. Class False Boolean Methods False ifTrue: trueBlock ifFalse: falseBlock ^falseBlock value | not ^true | xor: aBoolean ^aBoolean | printString ^'false' ]
03G-23Cooperation responsibilities Cooperation requires a division of responsibilities The class Context cooperates with Block and Method Responsibilities: Block and Method : provide the data necessary for the computation Context : executes the computation and returns the result Thanks to cooperation, the functionality of Context may be shared by Block and Method without change The class Link cooperates with List Responsibilities: Link : provides a recursive implementation for the basic methods of List List : treats the special case of empty list and implements composite methods Thanks to cooperation, some operations may be easily implemented by List, e.g., reverseDo :
03G-24 Block and Method Class Block Object context argCount argLoc bytePointer Methods Block value: x ^ (self checkArgumentCount: 1) ifTrue: [ context at: argLoc put: x. context returnToBlock: bytePointer ] ] Class Method Object text message bytecodes literals stackSize temporarySize class watch Methods Method executeWith: arguments ^ ( Context new ; method: self ; temporaries: ( Array new: temporarySize) ; arguments: arguments ) returnToBlock: 1 ]
03G-25 The Class Context Class Context Object linkLocation method arguments temporaries Methods Context method: m method <- m | arguments: a arguments <- a | temporaries: t temporaries <- t | at: key put: value temporaries at: key put: value | returnToBlock: bytePtr | blockReturn ifFalse: [ ^ smalltalk error: 'incorrect context for block return'] ]
03G-26 Removing an Element Class List Collection links Methods List remove: value (links notNil) ifTrue: [ links <- links removeValue: value ] ] Class Link Object key value nextLink Methods Link removeValue: aValue (aValue = value) ifTrue: [ ^ nextLink ] ifFalse: [ (nextLink notNil) ifTrue: [ nextLink <- nextLink removeValue: aValue ] ]
03G-27 Doing in Reverse Class List Collection links Methods List reverseDo: aBlock (links notNil) ifTrue: [ links reverseDo: aBlock ] ] Class Link Object key value nextLink Methods Link reverseDo: aBlock (nextLink notNil) ifTrue: [ nextLink reverseDo: aBlock ]. aBlock value: value ]