380 likes | 552 Views
Everything is an Object. Examining some builtin classes All these are classes in Squeak Object Class Method ,Block files, editors, compilers, tools Boolean True False Run time type information Implementation of new Printing objects. Learning Squeak.
E N D
Everything is an Object • Examining some builtin classes • All these are classes in Squeak • Object • Class • Method ,Block • files, editors, compilers, tools • Boolean • True • False • Run time type information • Implementation of new • Printing objects
Learning Squeak The best way to learn Squeak is to explore the definitions of builtin classes. A file containing the implementation of any class may be produced by clicking File Out on a class or an entire category. The result is a file containing smalltalk code Such files can be Filed In using the file list browser.
The Class Object • The class Object is the root of Squeak’s hierarchy. • It inherits fromProtoObject, but we currently ignore this class • Most other classes inherits from it, directly or indirectly. • The existence of a single root is useful to assure that some messages are understood by any object. • Object defines about 400 methods • 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. • Some methods are implemented by calling primitives. A primitive is a kind of external function. • The class Object is an Abstract Class. • Question: What is the superclass of ProtoObject?
Objects’ Printability • The method printString provides a common behaviour. Its implementation is based on the method printStringLimitedTo:which is based on printOn:. printString ^ self printStringLimitedTo: 50000 printStringLimitedTo: t1 | t2 | t2 := String streamContents: [:t3 | self printOn: t3] limitedTo: t1. t2 size < t1 ifTrue: [^ t2]. ^ t2 , '...etc...‘
Objects’ Printability – Cont. The method printOn:provides a default behaviour. The default is returning the name of the receiver’s class. printOn: t1 | t2 | t2 := self class name. t1 nextPutAll: (t2 first isVowel ifTrue: ['an '] ifFalse: ['a ']); nextPutAll: t2 The method class is implemented by a primitive. class <primitive: 111> self primitiveFailed Override printOn: to give your objects a sensible textual representation
Fraction >>PrintOn: printOn: aStream aStream nextPut: $(. numerator printOn: aStream. aStream nextPut: $/. denominator printOn: aStream. aStream nextPut: $).
Equality Tests The method == of ProtoObject returns true if the receiver and argument are the same object. It is implemented by a primitive. == t1 <primitive: 110> self primitiveFailed The method ~~ is based on ==. It needs not be overridden. ~~ t1 self == t1 ifTrue: [^ false]. ^ true The method = returns true if the receiver and argument are objects with the same value. It must be overridden. = t1 ^ self == t1
Collection’s Equality • The class SequenceableCollection overrides the method = = t1 self == t1 ifTrue: [^ true]. self species == t1 species ifFalse: [^ false]. ^ self hasEqualElements: t1 SequenceableCollection provides a default behaviour that is more appropriate for its subclasses • The method = in class Complex = anObject anObject isNumber ifFalse: [^false]. anObject isComplex ifTrue: [^ (real = anObject real) & (imaginary = anObject imaginary)] ifFalse: [^ anObject adaptToComplex: self andSend: #=]]
Copying Objects • The method shallowCopy returns a copy of the receiver. • a shallow copy of an object shares its references to instance variables with the original object. • The method shallowCopy provides common behaviour, based on methods basicSize and basicAt:, which are implemented by primitives. • The method copyTwoLevel copies also first level of instance variables • i.e, makes a shallow copy of each variable • The method deepCopy copies also all of the objects within the receiver, recursively. It must be overridden. • Bug: deepCopy will not terminate when applied to a mutually recursive structure:
Copy – Cont. The method copy may be either a shallow or a deep copy, depending upon what is appropriate for the receiver. copy ^self shallowCopy postCopy Override postCopy to copy any instance variables that should not be shared.
Copy in Dictionary The class Dictionary overrides the method copy. copy ^ self shallowCopy withArray: (array collect: [:t1 | t1 ifNotNil: [Association key: t1 key value: t1 value]])
Objects in Squeak • Everything is an object • Things only happen by message passing • Variables are dynamically bound • State is private to objects • Encapsulation boundary is the object • “protected” for subclasses • Methods are public • “private” methods by convention only • (Nearly) every object is a reference • Unused objects are garbage-collected • Single inheritance
Squeak’s Object Model • Rule 1:Everything is an object. • Integers are objects • 3 + 4 "send '+ 4' to 3, yielding 7" • 20 factorial "send factorial, yielding a big number" • Classes are objects • Rule 2: Every object is an instance of a class. • A class specifies the structure and behaviour of its instances • Instances of a class share the same behavior and have a specific state • The class of an object can be obtained by sending it the class message • 1 class -> SmallInteger • 20 factorial class -> LargePositiveInteger • 'hello' class −> ByteString • #(1 2 3) class −> Array • (4@5) class −> Point • Object new class −> Object
Squeak’s Object Model - cont • Rule 3:Every class has a superclass. • Each class inherits its behaviour and the description of its structure from a single superclass. • SmallInteger superclass −> Integer • Integer superclass −> Number • Number superclass −> Magnitude • Magnitude superclass −> Object • Object superclass −> ProtoObject • ProtoObject superclass −> nil • Rule 4:Everything happens by message sends. • Rule 5:Method lookup follows the inheritance chain. • The class of the receiver looks up the method to handle the message. • If this class does not have a method, it asks its superclass, and so on, up the inheritance chain. • If method is not found, the object sends self doesNotUnderstand: #<message name>.
Metaclasses in 7 points • Every object is an instance of a class • Every class eventually inherits from Object • Every class is an instance of a metaclass • The metaclass hierarchy parallels the class hierarchy • Every metaclass inherits from Class and Behavior • Every metaclass is an instance of Metaclass • The metaclass of Metaclass is an instance of Metaclass
Every class is an instance of a metaclass • Classes are objects too! • Each class X is the unique instance of its metaclass, called X class Object class Object Magnitude class Magnitude Number class Number Integer class Integer anInteger Instance of
Metaclasses • Metaclasses are implicit • There are no explicit metaclasses • Metaclasses are created implicitly when classes are created • No sharing of metaclasses (unique metaclass per class) • Metaclasses are anonymous • Can be referred to through the class that is their instance • Integer class Integer class • Object class Object class
The metaclass hierarchy parallels the class hierarchy Object class Object Magnitude class Magnitude Number class Number Integer class Integer anInteger Instance of
Every metaclass inherits from Class and Behavior Behaviour ClassDescription Class Object class Object Magnitude class Magnitude Number class Number Integer class Integer anInteger Instance of
Every metaclass is an instance of Metaclass Behaviour ClassDescription Class Object class Object Magnitude class Magnitude Metaclass Number class Number Integer class Integer Instance of anInteger
Every metaclass is an instance of Metaclass Behaviour ClassDescription Metaclass class Class Object class Object Magnitude class Magnitude Metaclass Number class Number Integer class Integer Instance of anInteger
Inheritance Instance of
Class Attributes • Some of 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 side of a class • The most important method is the one that makes the class able to generate new instances. • When the message new is sent to a class • it is looked up in its metaclass chain and ultimately in its superclass: Behavior
The Method New • The method new is first defined in the class Behavior, and can be redefined in its subclasses, including any metaclass of classes we define. • new always returns an instance of self, the class that receives the message, even if it is implemented in another class. • new first creates a new instance and then sends to it the message initialize: new ^ self basicNew initialize • basicNewallocates an instance using a primitive. • new is redefined in Metaclass: new thisClass class ~~ selfifTrue: [^ thisClass := self basicNew].self error: 'A Metaclass should only have one instance!'
Method Lookup Two step process: • Lookup starts in the class of the receiver (an object) • If the method is defined in the method dictionary, it is used • Else, the search continues in the superclass • If no method is found, this is an error…
Looking for Methods • respondsTo: is defined in Object as: respondsTo: t1 ^ self class canUnderstand: t1 • canUnderstand: is defined in Class as: canUnderstand: t1 (self includesSelector: t1)ifTrue: [^ true].superclassifNil: [^ false].^ superclasscanUnderstand: t1
Run-Time Type Information • Since Smalltalk is dynamically typed it is useful to ask about the identity of the objects. • The methods isMemberOf: and isKindOf: defined in Object may be used for type checking. isMemberOf: t1 ^self class == t1 isKindOf: t1 self class == t1 ifTrue: [^ true]. ^ self class inheritsFrom: t1
Design Techniques • The builtin classes of Squeak provide several examples of design techniques that are characteristic of Object Oriented Programming. • Some of these techniques are: • Providing additional functionality using composite methods, implemented over basic ones. • Example: The reject: class Collection. • The use of abstract classes implementing the common behavior of its subclasses. • Example: The classes Boolean, True and False.
Composite Methods • A class should provide to its clients all the functionality that may be useful, even if not absolutely necessary. • The protocol of a class may be extended by the addition of composite methods, implemented over basic ones. • The implementation of these additional methods requires very little effort, but makes the class more powerful. • The main advantages of composite methods are: • The interface of the class becomes more abstract. • The protocol of the class becomes more complete. • The class becomes more useful. • The class becomes easier to use. • Composite methods improve reusability.
The Class Collection The basic method select: is used to implement the composite methods reject: select: aBlock | newCollection | newCollection := self species new. self do: [:each | (aBlock value: each) ifTrue: [newCollection add: each]]. ^newCollection reject: t1 ^ self select: [:t2 | (t1 value: t2) == false]
Abstract Classes • Abstract classes are normally derived by the generalization of its subclasses. • They provide a common behavior for their subclasses. • 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. • The methods implemented in an abstract class are reused by its subclasses.
The Class Boolean The class Boolean is an abstract class: ifTrue: t1 self subclassResponsibility !! ifFalse: t1 self subclassResponsibility !! ifTrue: t1 ifFalse: t2 self subclassResponsibility !! ifFalse: t1 ifTrue: t2 self subclassResponsibility
The Class True The class True inherits the functionality of Boolean. ifTrue: t1 ^ t1 value !! ifFalse: t1 ^ nil !! ifTrue: t1 ifFalse: t2 ^ t1 value !! ifFalse: t1 ifTrue: t2 ^ t2 value
The Class False The class False inherits the functionality of Boolean. ifTrue: t1 ^ nil !! ifFalse: t1 ^ t1 value !! ifTrue: t1 ifFalse: t2 ^ t2 value !! ifFalse: t1 ifTrue: t2 ^ t1 value
The Class Boolean Taken from Little Smalltalk, could be applied in Squeak Class Boolean Object Methods Boolean ifTrue: trueBlock ^self ifTrue: trueBlockifFalse: [] | ifFalse: falseBlock ^self ifTrue: [] ifFalse: falseBlock | ifFalse: falseBlockifTrue: trueBlock ^self ifTrue: trueBlockifFalse: falseBlock | and: aBlock ^self ifTrue: aBlockifFalse: [ false ] | or: aBlock ^self ifTrue: [ true ] ifFalse: aBlock ]
The Class True Taken from Little Smalltalk, could be applied in Squeak Class True Boolean Methods True ifTrue: trueBlockifFalse: falseBlock ^trueBlock value | not ^false | xor: aBoolean ^aBoolean not | printString ^'true' ]
The Class False Taken from Little Smalltalk, could be applied in Squeak Class False Boolean Methods False ifTrue: trueBlockifFalse: falseBlock ^falseBlock value | not ^true | xor: aBoolean ^aBoolean | printString ^'false' ]