Previous | Table of Contents | Next |
What distinguishes Smalltalk from most other languages at the time is that other languages discard the intermediate representation and only save the machine code, whereas Smalltalk saves only the intermediate representation. In this way, Smalltalk applications could be fully portable across a wide range of processors, able to store code in very compact form, and still retain much of the speed of machine code. In order to make this space/speed tradeoff, Xerox Smalltalk implementations generated code on demand and kept a relatively small cache of machine code.
The Smalltalk-80 class library in the virtual image was created by rewriting Smalltalk-76 in situ. We kept the system running at all times and rewrote major system classes by category (such as magnitudes, arithmetic objects, strings, and collections). With each category of revision, we invoked what we called a junta. We took advantage of the Smalltalk capability of metamorphasizing objectsas though time stood still, all instances of one class could become instances of another class. For example, all existing strings in the system could become instances of the new string class. We changed the syntax so that the character set corresponded to a standard ASCII character set, removing the requirement that target Smalltalk machines be capable of handling pictorial fonts.
One of the most interesting changes to Smalltalk was to finally create a system in which everything truly was an object with all processing done as messages to an object. Thus control structures were implemented as messages to an Integer, Interval, Block, or Collection object, as shown in the following list (note that := denotes assignment):
Simple repetition | 10 timesRepeat: | |
[joe turnBy: 10]. | ||
Conditional | (number \\ 2) = 0 | |
ifTrue: [parity := 0] | ||
ifFalse: [parity := 1]. | ||
Enumerated iteration | 5 to: 25 by: 2 | |
do: [:arg|joe growBy: arg]. | ||
#(joe mary sam) | ||
do: [:arg|arg print]. | ||
while loop | [joe direction < 180] | |
whileTrue: [joe turnBy: 5]. | ||
index := 1. | ||
[index > list size] whileFalse: | ||
[list at: index put: 0. | ||
index := index + 1.]. | ||
Other enumerations create new collections | ||
Answers | #(2 3 5 7 11) collect: | |
#(4 9 25 49 121) | [:prime|prime*prime] | |
Answers 4 | letters := #(a B d a F G q S a A). | |
(letters select: [:each | ||
each asLowercase==$a]) size. | ||
Answers 6 | (letters reject: [:each| | |
each asLowercase~~$a]) size. |
For everything to be an object, a class itself must be an object. As every object is an instance of a class, then a class must be an instance of a class. In Smalltalk-80, we called the class of the class a metaclass.11 The class of a metaclass must be a metaclass as well. In Smalltalk-76, the structure was simpler. Every object was an instance of a class. Every class was an object and therefore had to be an instance of a class as well; we called that class simply Class. Class Class, by necessity, was an instance of itself. All classes in the system formed a single class hierarchy, with the topmost superclass called Object. Class Class was a subclass of class Object; class Object was an instance of class Class. This relationship is shown in Figure 3.1.
11See Kiczales et al. (1991) for a full treatment of the use of metaclass protocols.
FIGURE 3.1. Smalltalk-76 class relations.
The Smalltalk-76 class hierarchy supported differentiating behavior for instances of different classes. It did not support the capability to define behavior specific to different classes, in particular, initialization behavior. Creation of a metaclass hierarchy allowed us to solve the instance creation problem without mixing in the use of functions, as we had done in Smalltalk-76. But it also caused us to create a complex set of relations, which is hard for beginning Smalltalk programmers to understand. Figure 3.2 is a diagram of the top of the Smalltalk-80 hierarchy; it shows how metaclasses, classes, and instances are related. The particular problem we solved was how to handle the creation message as a proper message to an object, and how to force proper initialization of instance variables. You send the message new (or some other appropriate message) to the class object to create an instance of itself. The class object then sends that newly created instance a message, such as initialize. Every class then can implement its own initialize message to provide default values for instance variables. The metaclass hierarchy provides the objects that can know these initialization behaviors.
FIGURE 3.2. Smalltalk-80 class relations.
Previous | Table of Contents | Next |