Note that this tutorial uses Squeak's appearance and functionality in all its examples. While there are major differences to modern commercial implementations (e.g. VisualWorks and IBM Smalltalk) Squeak uses standard Smalltalk syntax and its programming tools and class library are very close to the Smalltalk systems reported in the original series of books.
Some links to other tutorial resources:
Building an application
What to do next ?
Smalltalk's roots reach back to the early seventies when many ideas later incorporated into the Smalltalk/ObjectWorks programming system were first explored in the context of the Dynabook project at the Xerox Palo Alto Research Center (Parc). This "Dynabook" was based on a vision of inexpensive notebook-sized personal computers for both adults and children, with the power to handle all their information-related needs. Prior to joining Xerox Parc, Alan Kay, the main advocate of this idea, worked at the University of Utah, where he was part of a team which developed the Flex programming system, a novel design for a flexible simulation- and graphics-oriented personal computer, with many ideas derived from Simula and Sketchpad. When Kay proposed an extension as this research to Parc's board of directors, his design was well beyond the capacilities of computer hardware and software technology at the time. The Dynabook was based on the assumption of ample memory and processing power, as well as a flat-screen display sensitive to the touch of a finger. For sound reproduction it was meant to be plugged into a stereo system, and for access to large shared data bases there was a connection to telephone lines. Kay firmly believed that Dynabooks would prove just as revolutionary as the affordable personal books which replaced the handmade texts of the middle ages after Gutenberg's invention of the printing press. He envisioned a multitude of uses for such devices, in areas as diverse as the drawing of pictures (e.g. for pre-school children), storage of information (e.g. for doctors), instrumentation of music (e.g. for composers), the dynamic simulation and graphical animation of models (e.g. for teachers), the representation of objects in three-dimensional-space (e.g. for architects), or the computation of inventories and cash-flows within a company (e.g. for business people). In order to fully exploit the potential for interaction offered by the new medium, some degree of programming skills would be expected from users. Existing programming languages, however, were designed for specialists and were largely only appropriate for numerical tasks ; exactly those kinds of applications which Kay saw as relatively uninteresting for the style in which he expected the Dynabook to be used. Languages in the Lisp family, although they offered the necessary symbol processing power, were still lacking in constructs for data encapsulation and did not cater for easy extension by non-specialist users.
Development of a new programming language was therefore given a high priority. At around the same time S. Papert and a group of other researchers were also working on an interactive and highly graphical computer-based learning environment called Logo, which they intended to use to teach programming to children. Logo was based on J. Piaget's work in developmental psychology, and Kay adopted many of its central ideas. Programming in procedural languages often requires elaborate combinations of procedures, and the complexity of getting such constructs to work increases exponentially with the length of the program. Since the whole idea of a "dynamic" personal computing medium was crucially dependent on features for easy extension of concepts by non-specialists, Kay opted for a building block approach of layered design, built around the notions of encapsulation and inheritance. Smalltalk was the programming language which finally emerged. It was the first computer language based entirely on the notions of object and messages.
The Dynabook project was never successfully completed, although many of today's notebook computers have reached and gone beyond its original goals. Much of the research done at Xerox Parc during the years of the project's existence, however, has had a tremendous influence on many areas of computing. The first experimental implementations ran on the so called Alto workstation, a modified Data General Nova minicomputer. This was later replaced by the Dorado, a custom-built and very fast personal computer . At the time of their development both these computers were at the cutting edge of technology. Research at Xerox Parc also pioneered the ideas of memory-mapped black on white graphics (replacing the traditional green on black CRT display) and the Ethernet architecture for local area networks. On the software side, many innovative ideas on the use of window-based, mouse- and menu-driven user interfaces were first experimented with over a period of many years.
Smalltalk, the Dynabook's programming tool, was originally envisioned as a simple language suitable for use by children without any prior knowledge of computers. The choice of name reflects this intention. The very first Smalltalk system was a thousand lines Basic program, which successfully computed 3+4 in October 1972. It was followed by an assembly code implementation which became known as the Smalltalk-72 system two months later. D. Ingalls was the chief implementor of these systems. In 1974. Smalltalk was ported to the Alto computer and a number of experiments in building graphical user interfaces were performed. Applications included turtle graphics, a mouse-driven program editor, a structured graphics editor, an animation system and a music system. Smalltalk-72 also served as a base for experimental programs in teaching object-oriented programming to high-school children . Smalltalk-74 added better facilities for bit-mapped graphics (class BitBlt) and virtual memory. This improved system was used to implement an information retrieval system and a window-based user interface. Smalltalk-74 evolved into Smalltalk-76, which was based on a much cleaner design. Smalltalk-76 also added the idea of inheritance, which had been absent from the two earlier systems. The concept of "byte codes" as a base for portable implementations was proposed and a micro-coded emulator for this design resulted in much improved performance. Smalltalk-76 was used on a daily basis by more than 20 people for a period of 4 years. A further clean-up of the implementation (Smalltalk-78) then led to Smalltalk-80, the first system which was made available outside Xerox Parc.
During the 8 years of Smalltalk's early development occasional publications by members of the "learning research group" and reports by visiting researchers had raised a considerable amount of interest. Attempts to obtain more detailed information, however, usually ended in frustration . In 1979 and 1980 Xerox finally agreed to Smalltalk-80's public distribution. This process was planned to proceed in three stages: a series of introductory articles, a book with detailed system specifications, and a tape with a portable implementation. The introductory articles were published in a special issue of Byte magazine . The plans for the detailed system specification were revised to a series of four books. The first of these (the so called "Blue Book") describes the language and its implementation. The second (called the "Orange Book" ) offers a detailed discussion of Smalltalk's user interface. The third book was meant to describe how to use Smalltalk as a tool for graphical and interactive applications, and the fourth book (the so called "Green Book" ) was intended to serve as an aid to implementors. Unfortunately the third of these texts was never published, which left a major gap in the documentation on how to use the system for a long time.
The software for the portable implementation was divided into two major parts, the Virtual Machine and the Virtual Image. The Virtual Image (VI) is the collection of classes encoding Smalltalk's functionality. This includes definitions of data structures, graphics and text handling, compiler, decompiler, debugger, viewing and user interface support. It was machine independent in the sense that all definitions were given in Smalltalk itself, while the compiler generated code in an intermediate language called "byte codes". The Virtual Machine (VM) formed the machine-dependent part of each implementation, consisting of a byte code interpreter, a storage manager and a number of "primitive "methods . Provided an appropriate Virtual Machine could be written, Smalltalk could now be ported to any platform that offered support for bit-mapped graphics and a pointing device. Xerox retained the copyrights to the system and any unauthorised reproduction and distribution was prohibited. In order to test the system's portability before wider distribution was attempted, an invitation was made to a number of computer companies to develop pilot implementations on suitable equipment. Four of the companies which accepted the invitation eventually produced working systems: Apple Computer, Digital Equipment, Hewlett Packard and Tektronix. This process weeded a number of errors out of the system and in 1983 a new version (VI2) was finally distributed to a wider community. Once the system's public distribution had begun Xerox Parc started to cooperate with Fairchild's laboratory for AI research on an improved design for a Smalltalk implementation for the Motorola 68000 microprocessor. This resulted in a system called "PS Smalltalk", which formed the base for Parc Place system's current Smalltalk products. Smalltalk projects were also initiated in Japan and Europe. For some time Tektronix retained an active involvement in the language and offered a whole range of Smalltalk-based workstations. They also supported a group of researchers responsible for many interesting innovations to the system. Apple computers also had a strong interest in Smalltalk. In the early eighties a number of the original members of the learning research group (including L. Tesler and D. Ingalls) joined Apple's effort to design and implement a new computer architecture strongly based on ideas taken from the Smalltalk environment. This project led directly to the Lisa and MacIntosh microcomputers . It should therefore not be surprising that many ideas in the MacIntosh user interface turned out to be very similar to Smalltalk.
Among a number of early Smalltalk implementations for IBM equipment, Digitalk's Smalltalk V was the only one which survived. Smalltalk V and later Visual Smalltalk restricted itself to a much simplified user interface, due largely to hardware constraints on early IBM PCs and Microsoft's DOS operating system, but it was sold for a very reasonable price .Xerox itself reaped only sparse rewards from its investment in the Smalltalk project. Some early Smalltalk workstations (Xerox 1100 series) were overpriced and sold only in small numbers. The Star machine, an advanced office computer based on ideas from the Smalltalk interface, never became popular for the same reasons. In 1987 Xerox decided to corporatise its Smalltalk interests. A separate company named Parc Place systems was founded and became responsible for further development and distribution of Smalltalk licences and systems. This new company employed some of the members of the original Smalltalk team and released a number of improved implementations (VI 2.2 , 2.3, 2.4, 2.5) on computer systems as diverse as Apple MacIntoshes, IBM PCs and Sun workstations. In 1990 a new version of Smalltalk, called ObjectWorks and later VisualWorks, was introduced, offering colour and a portable interface which makes use of its hosts "native" window managers . This required a major rearrangement of functionality between Smalltalk's Virtual Machine and the host machines' operating systems, which has resulted in a completely redesigned language in which applications are highly portable across a wide range of computing equipment. Recently Parc Place system has merged with Digitalk, and the combined company is busily working on a new joint implementation codenamed "van Gogh". Three years ago IBM also joined the rank of mayor Smalltalk vendors. Its VisualAge Smalltalk shows only minor differences to VisualWorks.
While the above are commercial systems with often hefty price tags, a few public domain Smalltalk derivatives such as Smalltalk X, Dorado Smalltalk and Squeak have emerged since 1996. Among these Squeak is of particular interest, since it is under active development by a small group of researchers, including Smalltalk's original founding fathers Alan Kay and Dan Ingalls. The project is led by Dan Ingalls, while Kay funds it in his role as a Disney fellow. In many ways Squeak represents a return to the values of the original Smalltalk project. Its design is based on Smalltalk 2.5, augmented with a more modern color graphics model and implementation technology. As it continues to develop further it may move into different areas - e.g. its latest release contains an experimental user interface architecture called Morphic (adopted from Sun's discontinued Self project). Squeak is freely available and currrently implementations for MacIntoshes (XXX), Windows PCs (XXX) and Unix systems (XXX) exist. There is also a Squeak mailing list which keeps its user community abreast of latest developments.
Squeak has been chosen as a programming tool for COSC205 mainly because Smalltalk is a purely object oriented language with little syntactic baggage, and Squeak offers a freely accessible and protable implementation of its ideas. In addition it is compact, efficient and fun :)
Smalltalk is a purely object-oriented language which cleanly supports the notion of classes, methods, messages and inheritance.
All Smalltalk code is composed of chains of messages sent to objects. Even the programming environment itself is designed within this metaphor. A large number of predefined classes are collectively responsible for the system's impressive functionality. Different from most other programming tools all of this functionality is always accessible to browsing and change, a fact which makes Smalltalk an extremely flexible system, which is easy to customize according to one's own preferences. There are some so called "primitives", but this is only because some operations are implemented directly in machine code for efficiency reasons. Normally this applies to basic arithmetic, graphics and other I/O operations, comprising less than 5% of a typical Smalltalk system's code. Even these primitives are not immutable, however, since their definition may always be overridden if one is willing to pay a performance penalty.
The system's basic functionality is rooted in the so called Model, View, Controller metaphor, where the phrase model refers to those pieces of code which describe all logically related structural and behavioural aspects of a specific application; a "program" in a conventional sense. A view is a screen representation for a model, which will typically reside in a window and reflect some of the model's aspects in textual or graphical form. Those two concepts are orthogonal in the sense that more than a single view of a model may be active at any given point in time. Controller entities, finally, offer the means for user interaction. To a beginning Smalltalk programmer the distinction between models, views and controllers may well remain hidden for quite some time. Although it is not too difficult to write specialized view and controller objects, there are enough standard components to suit many purposes. In fact, good Smalltalk programming style strongly encourages judicious modification of existing code in preference to the creation of new programs. This requires code-reading skills and an environment where class descriptions and their documentation are readily accessible for browsing and modification.
The desktop metaphor has shaped the way in which Smalltalk offers access to programs. In the following sections we will discuss and illustrate some of Smalltalk's syntax as well as its interface's major components. A more thorough treatment or any attempt at completeness in surveying the built-in functionality (class libraries) of the system, however, is beyond the scope of this summary. [Goldberg, 1983] and [Goldberg, 1984] are standard technical references, as are the 2 volumes by LaLonde and Pugh (1990) .
The above figure shows a snapshot of a Smalltalk desktop for a typical project. In addition to a few collapsed widows three open views are visible in overlapping windows on this screen. There is a "transcript" window, which is used by the system to show and record various kinds of status information and can also be written into by users, a "workspace" for evaluating Smalltalk expressions , and a "browser" for viewing code. Here the workspace holds an expression which asked the system to display a string in the transcript, and the browser is positioned to show the isEmpty method contained in the "testing" category of instance methods attached to class "Collection" in class category "Collections-abstract".
Smalltalk requires a pointing device for system/user interaction; this is usually a mouse. The original device connected to the Alto and Dorado machines had 3 buttons labelled "yellow", "red" and "blue", a convention which is still used to refer to them. If a three button mouse is not available on a particular host it must be simulated via mouse button/control key combinations or in some other way. The MacIntosh implementation, for example, uses a single mouse button, whose function is determined by context; i.e. the menus it invokes depend on the cursor's location or another key being pushed at the same time.
The so called "red" button is used to select information, while the "yellow" button invokes menus for manipulating a view's contents. Finally, the "blue" button menu offers a number of transformations on windows themselves (i.e. move, resize, relabel, ...). While the "blue" button choices are fixed, the specific contents of menus associated with the "yellow" mouse button depends on the cursor's position within a view and is defined by the viewed application.
The Smalltalk environment uses "pop up" menus in place of the "pull down" menus popularized by the Apple MacIntosh user interface. These have the advantage that they may be invoked at any place on the screen and are therefore more suitable for large display surfaces . A menu for selecting the "top level" functionality of the system is framed whenever the mouse button is pushed over an empty area of the screen . All menu items suffixed by "..." have suboptions, e.g. choosing "open" will offer a number of alternatives:
Workspaces offer a view of some piece of text. They are associated with a MacIntosh-like cut and paste editor and are often employed as a temporary "scratchpad", to enter and evaluate expressions during the process of testing new method definitions. In this case the window's body is just an area for entering text. As with any Squeak window, whenever the mouse is over the left-hand window border it will loose its "select" function and invoke a "red button" menu instead , offering a selection of choices for manipulating the view (see the "yellow button" menu above). Many Smalltalk views open into an information space of which only a part can be shown in a window, and they therefore have scrollbars to explore it further. Squeak's scrollbars appear at the left of a view and will open only when the mouse is inside it. The scrollbar attached to the workspace below indicates that there is currently no information hidden from view. If this were the case the black bar would turn to a rectangle which can be "grabbed" by the mouse and moved up and down to show hidden parts of the information.
The picture below shows another type (a so called "transcript") window and the "blue" button menu associated with it.
Transcript windows are text collectors, to which requests to display information may be sent. The "System Transcript" is a predefined entity used to display various system messages, and the global name 'Transcript' is permanently reserved for this object .
Workspaces permit expressions to be evaluated, in the way shown below. The relevant expressions should be selected by using the "select" button, and the "execute" menu may be invoked from within the workspace (as shown). This menu provides, among other options, two operations to trigger evaluation: doIt will send messages to the objects involved, while printIt will also show the returned value. As in Lisp all Smalltalk code must return some value. If not otherwise specified this will be the receiver of the last message. Here we send the message "+" , with an argument of '2', to the number '2'. The resulting value is highlighted in reverse video.
Workspaces and Transcript will suffice as a context for a brief summary of Smalltalk's syntax, and we will later return to discuss other user interface components.
Like other object oriented programming languages Smalltalk is built around the notions of classes, methods and messages, and is itself composed of a large collection of predefined classes, whose functionality may be invoked through message passing. Even the user interface is designed in this style, so that we can manipulate views by evaluating appropriate message expressions instead of selecting an option from a menu. For example,
answer := FillInTheBlank request:'Give me cookie !!! (please)'.
is a message expression in which request: is sent to class FillInTheBlank. This is a class in the Smalltalk library, which, in response, will create an instance of itself in the shape of a "query box" and display it on the screen. The user must then enter an answer (as a string) . This will be bound to a temporary local variable, answer (which must have been previously declared). The figure below shows the effect.
answer now has 'love' as its value. Please note that a view, framed in an appropriate window, has been created in response to a message rather than via menu selection.
Smalltalk offers numbers, characters, strings, symbols, arrays, classes and objects as basic primitives. Comments may occur at any place in the code, as long as they are enclosed by double quotes. Numbers are written in the usual fashion, and there are integers , floating point numbers and fractions as subclasses . Characters must be prefixed by a dollar sign, strings are enclosed in single quotes, (double quotes are used for comments) and elements of arrays are preceded by '#' and enclosed in parentheses .
7 "a number" $z "a character" 'colourless ideas sleep furiously' "a string" #(#tom #dick #harry) "an array of 3 components" #(#one 'should shower at least' 3 'times a week')
The last expression shows that elements in arrays need not be of the same type, since the array we use there contains 1 symbolic constant, 2 strings and a number. The effect of the # character is similar to Lisp's quote operator in that it inhibits evaluation of the symbols it is prefixed to. Below our mention of Snarfle causes an "undeclared identifier" response, with a menu of possible options to resolve this situation, while the previous uses of 'Snarfle' and #Snarfle simply referred to the string and the symbol itself. When viewing this figure it should be apparent that show: and cr messages sent to a text collector object (here the Transcript) cause a display of their arguments and carriage returns.
Smalltalk identifiers may contain any sequence of letters and digits, but must start with a letter. No other symbols are allowed. Smalltalk draws a syntactic distinction between local and global variables, in which all global identifiers must start with an upper case letter, while local ones will always begin in lower case. Class names are assumed to be global and must therefore always start in upper case. Smalltalk is a "dynamically typed" language in which there is no type information associated with identifiers, but rather with the objects themselves - as reflected in the classes they are instances of and consequently the types of messages they are willing to react to. Often, however, this information is only available at execution time and can not be inferred at the time a piece of code is "compiled" . Any object may therefore be bound to any identifier and type specifications are not required when variables are declared. However, all variables must still be defined prior to reference. Local variables may be bound as instance variables attached to an object, or they may be explicitely declared as temporaries. Such declarations for temporary variables are enclosed by vertical bars and separated by spaces.
|kermit skooter piggy henrietta|
declares four temporary variables. There is also an object called Smalltalk, holding references to all globally declared variables and we may use at:put: messages to enter new items.
Smalltalk at: #Kermit put: Frog new. Smalltalk at: #Piggy put: Pig new. Smalltalk at: #Henrietta put: Chicken new. Smalltalk at: #Skooter put: Mongrel new.
If not otherwise requested all variables are initialized to nil. The := symbol can be used to bind names to objects.
|fozzie| fozzie := Bear new.
creates a new instance of class Bear and binds it to "fozzie", after which we may proceed to send instance messages to him until he expires .
Message expressions are sequences of messages sent to objects, separated by periods. Messages names should indicate the type of action desired. They consist of selectors followed by their respective arguments, if any. Unary messages require no argument, while binary messages are written in the familiar infix notation. All other kinds of messages use keywords to name arguments.
"unary message to a class: 'new' returns a newly created instance of class CookieMonster" CookieMonster new. "binary message to an instance: '+' returns an instance of class integer (the sum)" 7 + 7. "keyword message to an instance: 'give:to:' prompts Skooter to perform a gallant deed" Skooter give: #flowers to: Henrietta
Messages can be nested , in which case some simple rules will apply: Parsing order is left to right, precedence is: unary -> binary -> keyword messages; parentheses must be used where necessary to disambiguate sequences. As a shortcut, messages sent to the same receiver can be "cascaded", using semicolons, so that
fozzie center; show; dance
would initiate a sequence of messages to fozzie; i.e. first causing him to center himself on the screen, display himself to his audience, and attempt some entertainment.
All of Smalltalk's data structures are respresented as objects, and a rich repertoire of these is available in its class library.
Object is the root of Smalltalk's inheritance hierarchy , providing some basic functionality to all objects. Class Collection is among class Object's many subclasses, and may itself be further specialized into a whole range of data structures. Sets are just one of these, with Dictionaries as a subclass. Dictionaries are used to store associations between pairs of objects. The code below shows the use of these data structures in a simple example. First a dictionary is defined, associating some old friends with a selection of virtues. Messages are then sent to this object, listing and searching for keys .
Smalltalk subscribes to a very strict interpretation of object orientation and even control structures are implemented as message patterns. Selection among alternative paths of execution is therefore supported through ifTrue:, ifFalse:, and ifFalse:ifTrue: messages. Loops may be specified with whileTrue:, whileFalse:, timesRepeat:, do:, to:do:, collect:, or via recursion. Smalltalk uses the notion of blocks to defer evaluation. Blocks may take arguments, can have temporary variables, and are used to encapsulate code which may be evaluated later. Among other things they are commonly used as arguments to control structures . Since they are objects themselves , blocks may be bound to identifiers. The value message forces a block's execution.
The workspace above shows 2 examples of how blocks are commonly used. The first case is a simple test, streaming over a range of numbers inside a loop. If a number is even, 'EVEN' is shown in the Transcript, and if it is odd, then 'ODD' should be printed there. Here we restrict our count to three, so that 0,1 and 2 will be tested. The task can be accomplished using a combination of whileTrue: and if..: messages. The thing to note is that both the receiver and argument must be blocks in the case of the whileTrue: structure, while only the argument must be a block in the case of ifTrue: and ifFalse: . The second example processes a list of symbols. A block describing appropriate actions is first constructed and named "canon". Here it should be noted that colons are used to prefix the names of the two block arguments, which are separated from the block body by a vertical bar. Any temporaries, if required , would follow after this. This block can now be executed as many times as desired, given different values as arguments . In our example the value:value: message forces evaluation for a three-voice chorus of dubious quality .
Recursive structures may be defined by objects sending messages to themselves. In the next section we will see some examples for this. Smalltalk's strong object-orientation also permits additional control structures to be defined in an elegant way, attaching appropriate methods to the class of objects which guards the control structures' execution. For example, if we intend a numeric value to control a selection or loop, then a corresponding method should be attached to class Number .
Smalltalk's syntax for class descriptions is shown in the lower pane of so called browser windows. Browsers are used to view existing as well as to define new classes. In accordance with the object-oriented philosophy each class functions as an interpreter for a command language of its own, whose functionality is defined through its message protocol; i.e. the set of all messages an object can respond to. Messages may be "understood" through methods defined within an object's class itself as well as through reference to methods inherited from superclasses. Smalltalk-80 supports a hierarchical scheme for inheritance, although "hooks" to implement multiple inheritance were available in earlier versions of the language. Class descriptions require a superclass, instance & class variables (if any), and instance & class methods. None of these parts are mandatory and a class without any of those, e.g.
Object subClass: #Dummy instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Sesame Street'
is perfectly valid . The notion of "poolDictionaries" is associated with so called "pool variables", an idea we will not pursue any furtehr here . Note that the distinctions between nstance variables and instance methods as well as class variables and class methods have been discussed in lectures.
Various categories of browsers play a very important role in Smalltalk. System Browsers are used to access definitions for all the classes and methods - both system-defined and user-defined - that Smalltalk knows about. They are also needed to define new classes and methods. Any number of system browsers may be opened on relevant collections of classes, and programmers will frequently switch between them to view, change, cut and copy code during development.
System browsers inhabit a window with five panes. The four upper ones are used for navigating a "path" through a space of definitions, while the lower one views the selected definition itself. To provide some structure to the large number of classes which can be found in a typical Smalltalk system all classes are grouped into categories. First we must enter a class category, which causes a scrollable list of classes categorized under that label to appear in the pane to the right. Choosing a class from this list narrows the browser's focus to all of its methods, which are now accessible for inspection. At this stage we must also decide whether we want to view class or instance methods. Methods are categorized in the same way as classes, and we must now choose a category. This finally returns a list of methods, which may now be selected - after which the relevant code is shown in the lower pane. Each of the five panes has its own "yellow" button menu, offering various options, as shown below. The options contained in the menu for the bottom pane could now be applied to all or any selected part of that code.
From this discussion it should be apparent that browsers offer a very powerful tool for viewing and accessing code, since they make all of the Smalltalk system uniformly accessible for inspection and modification.
Let us now step through the procedure by which one defines a new application. As our domain we have chosen a small segment of Sesame Street, a well known urban neighbourhood populated by a wide range of rather exotic creatures. To keep things simple we will concentrate on two classes of creatures only: Monsters and CookieMonsters. Monster is used as an abstract class, in order to demonstrate subclassing. It therefore describes a number of aspects common to monsters of all walks of life. CookieMonsters are just a special case, with certain peculiarities of their own.
Basically we view cookie monsters as entities who continually nag for cookies, which are the only food they ever consent to eat. Once awakened they may only be silenced once their immediate hunger has been stilled, after which they will fall asleep until some foolish user wakes them again. For these purposes monsters are characterized by a colour and a tummy. Since monsters come in a variety of colours, this information is stored as a symbol, and at creation monsters are equipped with an empty tummy instantiated to a predefined data structure called Bag . Apart from access to these two instance variables, monsters possess protocol to eat and answer whether their tummy is empty. The relevant instance methods are categorized as initialization, access, queries and actions . CookieMonsters specialize this protocol further. No additional class variables are defined, but two new instance variables, state and hunger, are provided. A CookieMonster's state will be either #awake or #asleep, and its hunger determined at random at the time it wakes up. We provide a class method for creating such beasts, together with instance methods for initialization, queries, access and actions. CookieMonsters eat differently from generic monsters, i.e. they are more choosy about their food. The generic monster's method for eating is therefore overridden by a new implementation for the eat: method. As they are not particularly strong they must also know how to solicit food by begging, and the "nag" method offers this functionality. Finally, there are methods for testing items prior to digestion, and for describing the particular way in which solicitation takes place. CookieMonsters view this information as proprietary, and it is therefore labeled as private .
To implement this scenario in Squeak we must first make a new class category, SesameStreet, add the Monster and CookieMonster classes, and then define and test all the methods. All these actions can be performed from within a browser, while workspaces and a new type of view, called inspector, may be employed for testing purposes. Figure 3.15 shows how to add a new class category (i.e. by choosing "add item" from the leftmost browser pane's yellow button menu and entering a string into a query box which opens in response.
Classes can be defined once the new category has been added to the system. For this purpose the lower browser pane will show a template for class definition, which the user may fill with detail. Choosing "accept" from the menu compiles the definition and adds it to the dictionary of classes the system knows about). NOte that choosing "update" from the leftmost browser pane's yellow button menu may sometimes be needed to force a browser to show the most recent changes.
Let us assume that we have successfully proceeded to define all class and instance methods for both monsters, and that the state of the model is now reflected by the figure below, which also shows the code for our CookieMonster's isFull method in the browser's bottom pane.
The next figure demonstrates the possibility of using more than a single browser simultaneously. In fact, the number of views on the desktop is limited only by the available memory. Multiple browsers are often useful to view different aspects of code at the same time, eliminating the need for constantly scrolling back and forth. By cutting and pasting, information may also be transferred between views. The first browser in the figure views the creation class methods currently defined for Monster. We need to override Object's standard instance creation method in order to make sure that our monsters' tummy and colour are initialized appropriately. Note the up-arrow symbol ("^") which indicates that the newly made monster will be returned as the value produced by this method. super is one of two so called "pseudo variables" (the other is self), which provide handles to the currently executing object (via self) and the message protocol of its superclass (via super). "^ super new initialize" will therefore send new to class Monster, followed by message initialize to the newly made monster , and will then return this instance in generic monster colour (i.e. green :) and with an empty bag as its tummy. The second browser is a so called class browser, which can be obtained by choosing "browse class" from the menu options accessible from the system browser's class pane. Class browsers restrict their perspective to the protocols of a selected class (here the class Monster) and their yellow button menus are the same as those of the corresponding panes of the system browser. The eat: method shown in this browser obtains a reference to the monster's tummy and stuffs some item into it. Since Smalltalk is a "dynamically typed" language one should take care to document clearly what kinds of objects a method expects as its arguments. Good Smalltalk style uses typenames prefixed by "a" or "some" (e.g. "anInteger", "someMonster") for this purpose, instead of less descriptive identifiers such as "x", "y" or "fred". This convention for naming arguments uses the name of the most general class of those objects a method is willing to accept. If we don't want to make any assumptions we can use : "someObject" or "someItem". Although it is only a convention and Smalltalk does not enforce it, the scheme serves well to simulate the documentation aspects of a "hierarchical" type system .
Although Monster is intended to serve as an abstract class, we may wish to create instances in the process of testing its protocol. Generally all methods added to classes should be tested immediately after they have been defined. Workspaces and inspectors support this activity. The next figure shows how to evaluate an expression (typed into a workspace) for making a monster and feeding a #nail to it. To convince us that our expectations are met we inspect the result afterwards . This will bring up a so called Inspector view, called "Monster", in which we can look at the values currently bound to all instance variables of the object we wish to observe . It is reassuring to note that the monster's tummy does now indeed hold a #nail. Inspectors may be invoked in various ways. While browsers permit traversal through a space of procedures, inspectors allow us to navigate through Smalltalk's data space.
We now proceed to complete the cookie monster's definition. Taking a shortcut we will not trace the whole process in detail, but will rather look at the state of the system at the time the CookieMonster's "top level" behaviour is tested. In a real application it would have been better to test each method as it was written, but space limitations prevent us from demonstrating this approach. The figure below shows an appropriate script, in response to which a notifier has just popped up, querying our usage of "Clara". Since this is not a global identifier known to the system it asks for guidance on how to interpret it . Since it should function as a new global instance of class CookieMonster we confirm the relevant option.
The next figure opens a browser on the CookieMonster's nag method and summarizes the sequence of events which unfolds after Clara awakes. As expected, she will immediately nag us for cookies . We offer her some, but maliciously also included some other, apparently undigestable items, which she rejects.
Again we look at the result of the feast in an inspector. Clara's hunger must have been set to 2 cookies. She is now sated and fast asleep.Note that since Clara is globally defined her state remains open for further inspection and we can also pursue further investigation of Clara's tummy, repeatedly choosing "inspect" from the relevant yellow button menus. This reveals that the bag serving as Clara's tummy is implemented as a dictionary, and the fact that item 'cookie' occurs 2 times is stored as a number associated with that key. Inspection then "bottoms out" at the number level, since numbers are literals and can not be inspected any further. .
The nag method shown in the bottom part of the browser in our final figure contains a whileTrue: loop, which is guarded by a test on the cookie monster's state. Within this loop it repeatedly asks for a 'cookie'. If one is offered, it is eaten. Any other item will be refused. This cycle will only terminate once the monster is "full", whereupon it falls asleep. The fourth browser pane's menu now allows us to browse all senders, all implementors, as well all references to class and instance variables. This functionality can often be very useful; for example, if changes to the method header should necessitate modification of messages sent somewhere else in the system, then it is easy to locate all these places .
We will now look at a summary of the completed code for classes Monster and CookieMonster.
Class: Monster Superclass: Object Category: Sesame Street Instance variables: colour tummy
"This ABSTRACT class implements some generic structure and behaviour common to different types of monsters."
eat: someItem self tummy add: someItem
isEmpty ^ self tummy isNil
colour ^ colour colour: aSymbol colour := aSymbol tummy ^ tummy tummy: aCollection tummy := aCollection
initialize self colour: #green. self tummy: Bag new
"There is only a single class method and no class variables."
new ^ super new initialize
Cookie monsters inherit from Monster, but add more specific behaviour of their own.
Class: CookieMonster Superclass: Monster Category: Sesame Street Instance variables: state hunger private
askForCookie ^ FillInTheBlank request: 'Give me cookie !!! (please)' complainAbout: anItem Transcript show: 'No want ', anItem printString. Transcript cr. self colour: #red isCookie: anItem " | serves as the OR operator" ^ ((anItem = 'cookie') | (anItem = #cookie))
eat: aCookie super eat: aCookie. self colour: #green nag | item | [self isAwake] whileTrue: [item := self askForCookie. (self isCookie: item) ifTrue: [self eat: item] ifFalse: [self complainAbout: item]. (self isFull) ifTrue: [self sleep]] sleep self state: #asleep. self hunger: 0 wakeUp self tummy: Bag new. self state: #awake. self hunger: (Random new next * 13). "Cookie Monsters are superstitious and never eat more than 13 cookies in one go !" self nag
isAsleep ^ state = #asleep isAwake ^ self isAsleep not isFull self isEmpty ifFalse: [^ self tummy size >= self hunger] ifTrue: [^false]
hunger ^ hunger hunger: anIntegerNumberOfCookies hunger := anIntegerNumberOfCookies state ^ state state: aSymbol state := aSymbol
initialize self state: #asleep. self hunger: nil. super initialize
To ensure proper initialization Monster's creation class method is also overridden.
new ^ super new initialize
You will have noted that most messages are rather short. In fact, a large proportion of them consists of a single line of code, returning (^) or assigning (:=) some value. This is typical for object-oriented programs and Smalltalk code in particular, since all valid patterns of access to variables must be explicitely defined. In the interest of reliability many state variables should not be accessible at all from outside of an object. Smalltalk's approach of requiring explicit method definitions for any access to variables is facilitated by its programming environment. Since the browser allows rapid definition of such selectors with only a few mouse clicks, modifying an already existing method, this is not particularly bothersome to do - and it pays in terms of program reliability. In a traditional listing such methods tend to clutter clutter the code, but browsers reduce the need for such tedious documentation.
Note that choosing "fileOut" fom the yellow button menu attached to the class category pane of a browser saves all such class definitions in the selected category as a text file (in the current directory), which can be "read back" into Squeak (i.e. each definition is recompiled) from a file list.