You do not have to read this chapter to get going with Smalltalk/V. One legitimate school of Smalltalk thought suggests that the best introduction to object-oriented programming is simply to jump right in--to learn Smalltalk by experience. If this notion appeals to you, proceed directly to Chapter 2. You may want to return here to supplement your experience. But there is nothing in this chapter that you have to know to understand and make effective use of Smalltalk/V.
If this were a book on driving a car, this Overview would describe a bit of the "physics" behind the car's engine, drive train and suspension--hardly prerequisite knowledge to the act of driving. But racing drivers will tell you that the more you know about how your car works, the better you can drive it--knowing how to pull maximum performance from the potential of the car's interacting component parts. If this notion appeals to you, proceed.
Smalltalk grew from a few powerful ideas.
Smalltalk embodies these ideas in a framework for human/computer communication. At the simplest level, Smalltalk is yet another programming language like Basic, C, Pascal or Lisp. You will see in this chapter how you can write Smalltalk programs that have the "look and feel" of conventional Pascal or other familiar programming languages.
You will also see how some thirty lines of Pascal, or less than twenty lines of "Pascalese" Smalltalk, can be reduced to five lines of Smalltalk the way it is meant to be written. And that's not five lines of dense, cryptic syntaxes like C or APL allows, coding shortcuts that come back to haunt you in application maintenance and enhancement costs.
If we try to build an ideal machine that lives up to the promise of the big ideas above, we would want a computing environment that is both very hardy and forgiving. If programming is to be a natural extension of thinking and learning, the system has to take programming errors in stride-a simple coding error can't crash the system or you'd lose all incentive to use an exploratory prototyping style of application development.
Smalltalk promotes the development of safe systems. Smalltalk "errors" are merely objects telling you they do not understand how to do what you are asking them to do-hardly events which blow up the system. And Smalltalk's encapsulation of digestible chunks of program code with their own local data in independently active objects promotes a "divide and conquer" approach to programming problem solving. Smalltalk objects are easily inspected, duplicated, modified and, perhaps most importantly, re-used. Smalltalk lets you get on to the business of solving your problem, not writing the same code over and over.
The Tutorials will introduce you to the range of programming "power tools" standard in Smalltalk/V that help you use, re-use and modify the storehouse of Smalltalk source code which is part of the basic system. But first, it can be helpful to understand that Smalltalk is both very much like and, at the same time, very much unlike conventional programming languages.
We'll then introduce you to some of the special terminology and exciting ideas that energize object-oriented programming in Smalltalk. From there it's on to the introductory tutorial which gets you up and running and writing your first Smalltalk/V code.
This section presents an overview of Smalltalk/V by comparing examples of code in both Smalltalk and Pascal to help you learn Smalltalk/V more quickly. You don't have to be a Pascal programmer to benefit from the comparison as thorough explanations accompany each example.
The step-by-step code examples are followed by a complete program written in both languages which solves the same problem. We conclude by rewriting the Smalltalk version of the algorithm, taking advantage of object-oriented features to significantly reduce the amount of code required to do the same procedure.
The examples which follow present a series of statements in Pascal and Smalltalk/V. The left column shows program fragments in Pascal, while the right column shows equivalent code fragments in Smalltalk/V.
Assignment to a Scalar Variable
a := b + c |
a := b + c |
These statements look the same in both Pascal and Smalltalk. The assignment operator is :=. Variable names have the same syntax in both languages. In the example statements, the contents of variable b are added to the contents of variable c and stored in variable a. In Pascal, the computed value is stored. In Smalltalk, assignment statements always store pointers to objects which contain the values (to use the Pascal terminology).
A Series of Statements/Expressions
x := 0; |
x := 0. |
y := 'answer' |
y:= 'answer'. |
z := w |
z := w |
The statement separator is semicolon in Pascal and period in Smalltalk. Note that in both languages, the statement separator character is not used after the last statement in the series. The first statement assigns the constant zero to the variable x. The second statement assigns a literal string to the variable . In both languages, a string is an array of characters. The third statement assigns the contents of variable w to variable z.
A Function Call with One Argument
a := size(array) |
a := array size |
The function size is called with argument array and the value returned is stored in the variable a. In Smalltalk, calling a function is known as sending a message. In this case, the message size is sent to the contents of variable array.
Function Calls with Two Arguments
x := max(x1, x2); |
x := x1 max: x2. |
y := sum(p, q) |
y := p + q |
In Pascal, the arguments to the function call are enclosed in parentheses. In Smalltalk, for a two-argument message, the arguments precede and follow the message name. When an argument follows a Smalltalk message name, the message name always ends with a colon (:). Note that in Smalltalk, standard arithmetic operations are performed via messages. In the first example, the message max: is sent to the contents of variable x1, with the contents of x2 as the argument. The result returned is assigned to the variable x. In the second example, the message + is sent to the contents of variable p with the contents of variable q as the argument, and the result returned is assigned to the variable y.
A Function Call with Three Arguments
b := between(x, x1, x2) |
b := x between: x1 and: x2 |
When a message has three or more arguments in Smalltalk, the name of the message is split into pieces, and a piece of the message name appears preceding each of the arguments.
This distribution of the message name helps to describe the message arguments. In the example, the message name is between:and: and the arguments are variables x, x1, and x2. This example could be used to test whether the value of x is between the values of x1 and x2, and assign the Boolean result (true or false) to the variable b.
Subscripted Variable Access
x := a[i]; |
x := a at: i. |
a[i + 1] := y-, |
a at: i + 1 put: y. |
a[i + 1] := a[i] |
a at: i + 1 put: (a at: i) |
Pascal uses square brackets to specify subscripting, whereas Smalltalk uses at: and at:put: messages. In the first example, the value of variable i is used to index the array identified by variable a, and the value obtained is stored in variable x.
The second example shows replacing an element of an array with a new value. Note that a Pascal assignment may store into an array element, whereas in Smalltalk only scalar variables appear to the left of an assignment statement, so an at:put: message is used.
The third example shows accessing and changing array elements. Parentheses are used in the Smalltalk example to specify evaluation order.
If Statements
if a < b then |
a<b |
a:= a + 1; |
ifTrue: [a := a + 1]. |
if atEnd(stream) then |
stream atEnd |
reset(stream) |
ifTrue: [stream reset] |
else |
ifFalse: [c:- stream next] |
c := next(stream) |
Pascal and Smalltalk provide similar capabilities for the conditional execution of a series of statements based on the result of evaluating a Boolean expression. In Smalltalk, the conditional statements are enclosed in square brackets. In the first example above, the variable a will be incremented by one if the value of variable a is less than the value of variable b.
The second example illustrates conditionally executed code during file access. The file being accessed is identified by the variable stream. If the file is positioned at the end; the reset message is sent to reposition it at the beginning. Otherwise, the variable c is assigned the next character in the file.
Iterative Statements
while i < 10 do begin |
[i < 10] |
sum := sum + a[i]; |
whileTrue: [ |
i := i + 1 |
sum := sum + (a at: i). |
end; |
i := i + 1]. |
for i := 1 to 10 do |
1 to: 10 do: [ :i | |
a[i] :=0 |
a at: i put: 0] |
Pascal and Smalltalk provide similar capabilities for repeated execution of a series of statements. In the first example, the two statements in the loop will be executed as long as the value of the variable i is less than 10. In the second example, the single statement in the loop will be executed with the variable i taking on the values 1 through 10 in succession.
Returning Function Results
functionName := |
^answer |
answer; | |
return |
Pascal and Smalltalk both provide for specifying the result of function (or in Smalltalk, method) evaluation. In Pascal, the function result expression is assigned to the function name, which serves as a variable for containing the result. In Smalltalk the caret (^) appears before an expression that is the method result. This causes method execution to cease and the value of the expression to be returned as the method result. In the example, the value of the variable answer is the function (and method) result.
Storage Allocation and De-allocation
new(p) |
p := Array new: 5 |
dispose(p) |
Pascal and Smalltalk both provide for the dynamic allocation of memory space to hold values (in Smalltalk terminology, objects). In the first line of the example above, both languages assign to the variable p a pointer to the newly allocated object. In Pascal, however, it is necessary to explicitly de-allocate objects when they are no longer needed in order to reclaim their space. This is done via the 'dispose' function call. In Smalltalk, space reclamation (garbage collection) is automatic; consequently there are no language facilities for specifying object de-allocation. This simplifies programming by eliminating a potential source of error: de-allocating at the wrong time.
A Complete Program
What follows is a complete program with Pascal code on the left, Smalltalk on the right.
Program frequency; | |
const | |
size = 80; | |
var | |
s: string[size]; |
| s c f k | |
i: integer; | |
c: char; | |
f: array [l..26] |
f := Array new: 26. |
of integer; | |
k: integer; | |
begin | |
writeln ('enter line'); |
s := Prompter |
readln(s); |
prompt: 'enter line' |
default: ' '. | |
for i := 1 to 26 do |
1 to: 26 do: [ :i | |
f [i] := 0; |
f at := i put: 0]. |
for i := 1 to size do |
1 to: s size do: [ :i | |
begin | |
c := |
c := (s at: i) asLowerCase. |
asLowerCase (s[i]); | |
if isLetter(c) then |
c isLetter |
begin |
ifTrue: [ |
k := ord(c) |
k := c asciiValue |
- ord('a') |
- $a asciiValue |
+ 1; |
+ 1. |
f [k] := f [k] + 1 |
f at: k put: (f at: k) + 1 |
end |
] |
end; |
]. |
for i := 1 to 26 do |
1 to: 26 do: [:i| |
write(f [i], ' ') | |
Transcript show:((f at: i) | |
end. |
printString, ' ')] |
The programs above ask the user to enter a line of text from the keyboard. Each program then computes the frequency of occurrence of each alphabetic character in the input text. All characters are treated as lower-case letters.
The example emphasizes the similarities of Pascal and Smalltalk syntax. The algorithm used is identical in both cases. The input characters are examined one at a time and if they are alphabetic characters, the frequency counter for that letter is incremented.
None of the powerful built-in building blocks of Smalltalk were used in the above example. The example below shows the same program written using some of these built-in building blocks.
| s f | s := Prompter prompt: 'enter line' default: ' '. f := Bag new. s do: [ :c | c isLetter ifTrue: [f add: c asLowerCase] ]. ^f
A Prompter is used to get the input string from the user. A Prompter is a special type of window. An empty Bag is then created to hold the character frequencies. Bags are a type of collection that count occurrences of objects. The input string is then iterated over, and each character is examined. If the character is a letter, its lower case equivalent is added to the Bag. The resultant Bag is then returned.
Already, Smalltalk is revealing its expressive power. The considerably shorter rewrite uses a few of Smalltalk's pre-defined objects, each with its own highly developed behavior. In the hundred sixty or so classes of Smalltalk/V, there are over three thousand methods you can call upon. Each new object and its methods, which you create, will be added on equal footing with the generic objects which come in Smalltalk/V.
Objects obviously have something to offer--a tremendous source of Smalltalk programmer productivity. A greater appreciation of what objects are and how they behave is in order.
Smalltalk is built on the simple yet powerful model of "communicating objects" as shown in Figure 1.1. What could be more natural? We experience our world largely as a vast collection of discrete objects, acting and reacting in a shared environment.
Figure 1.1
Communicating Objects
At the human social level we are a society of doctors, lawyers, beggars and thieves, etc. Although we are a population of unique individuals, we cluster in occupational groups based on the behavioral skills and knowledge we each develop and exhibit as seen below:
Figure 1.2
Human Occupational Classes
Break a leg, call in a doctor and tell him or her about your condition. You trust the doctor's special knowledge and skills to help make you better.
Want to become a lawyer? You learn the law and how to behave like a lawyer. Then as corporate counsel in response to the MegaCorp CEO's question, "What's our exposure on this new project?", your answer is couched in legal considerations while the chief financial officer reflects on fiscal impacts.
In Smalltalk's object-oriented terms, occupational abstractions like doctor, lawyer, programmer, etc., are classes of which we individuals are instances. To become a lawyer, we learn legal methods. Communications between individuals are comparable to Smalltalk messages, their content equivalent to Smalltalk selectors as shown in Figure 1.3. Correspondence between our perception of the world and its representation in machine terms through Smalltalk gets at the heart of Smalltalk's power.
Figure 1.3
Human and Smalltalk
Objects Communicating
A Smalltalk object is simply related pieces of code and data. The pieces of code are Smalltalk methods--a library of self-contained subroutines unique to each class giving each class of object its specific behavior. An object's data structure is described by its collection of instance variables.
When you create a specific instance of a class, the initial values of the object's instance variables are assigned. The object's methods are its know-how. If we were to create a Smalltalk "car driver object," it would likely include "brake," "steer," "watch for traffic" and "shift gears" methods. Instance variables of such a car driving object would include "reaction time," "temperament" and "visual acuity" of the driver.
Related data and program pieces are encapsulated within a Smalltalk object, a communicating black box. The black box can send and receive certain messages. Message passing is the only means of importing data for local manipulation within the black box. And if an object needs something done that it does not know how to do within its own set of methods, it sends a message to another object, in effect, asking for assistance in completion of a task.
In Smalltalk, objects communicate to objects just as lawyers talk to accountants in our occupational analogy in Figure 1.3. A professional's know-how is comparable to a Smalltalk object's collection of methods. People communicate using their know-how.
Know-how does not communicate to know-how. The lawyer's knowledge used to prepare a client's will does not include a "direct memory access" to the accountant's ability to compute financial implications of the settlement of an estate. Similarly, a Smalltalk object's methods do not call other object's methods directly. Rather, the lawyer's methods include knowing when to send a message requesting financial services, just as the CPA knows when and how to ask for legal services.
In OOPS terms, information hiding--as this encapsulation of code and data is known in computer science--makes for highly portable, easily modifiable and safe software. Large applications may be easily maintained since objects may be updated, recompiled, tested and called immediately back into service with their new behavioral capabilities on line.
Like their physical counterparts, Smalltalk objects have attributes and exhibit behaviors. Since everything in Smalltalk is an object--including the Smalltalk environment itself--what you can do with the language becomes a question of what objects can be described and manipulated.
If the encapsulation of information (hiding) provides the means for creating objects, then a language's data abstraction capabilities determine what objects can be described. Marco Polo called upon his powers of data abstraction daily as he traveled to parts unknown. Things which could not be understood or named within his current world view required invention, new words for new objects.
You need the same powers of an extendable language capable of describing arbitrary data structures if you are to tailor the generic Smalltalk environment to your purposes. Smalltalk lets you create arbitrary new data structures, compound objects which can be thought of as arrays whose elements can be any combination of numbers, symbols or character strings as well as other arrays, making nested data structures possible. Where it is generally an exception or nuisance in conventional languages, creating new data structures is done routinely when you define a new class or subclass of objects in Smalltalk.
Smalltalk objects take responsibility for their own actions, responding individually to every message. Your application may have occasion to print an integer, a floating point number, an ASCII character or a string of symbols. Since each of these elementary data types is defined as a Smalltalk class, instances of these classes come with a bundle of behavioral features built-in: its methods. Each of the elementary data types knows how to perform generally required behaviors such as print, duplicate and comparison operations.
So when it comes time to print, your Smalltalk application simply sends the near universal message printString to each of the variety of data type objects to be included in a report:
'This is a string' printString. 423 printString. #(123) printString. $A printString. #('array of ' 3 'strings and' 2 'numbers') printString.
Integers, arrays and characters take care of getting themselves represented on paper. This Smalltalk characteristic of having different objects responding uniquely to the same message is known as polymorphism. It means you won't have to memorize a unique vocabulary for each class used in building your applications.
Because Smalltalk objects take responsibility for their own behavior, you won't have to litter your application with conditional checks through case statements to see that the proper type of function is called to operate on a piece of data. This feature saves much time and significantly reduces software maintenance costs since only affected objects need be edited and re-compiled to enhance a Smalltalk application.
Among the many reasons objects communicate, a frequent objective is to change the state of the receiver object. Sending a message to store a new value in a variable (a Smalltalk variable is an object that stores other objects) is an obvious example of state changing messaging. A bit more subtle is a user request to resize a window which results in a mouse-based interaction which sends new screen coordinates to the window's instance variables which store its size and location on the screen. The window's state changes upon receipt of the resize message.
Smalltalk guarantees that there will be a response by a message recipient. If an object determines that it does not know how to perform a requested behavior, it will at least answer with a "Message not understood" response message. The method which sends this response also kicks in Smalltalk's debugging utilities to help you determine and correct the failure to communicate.
So even program errors are detected and resolved within the object-oriented messaging framework of Smalltalk. This makes for a very exploratory environment in which to develop application software. A working prototype can be constructed quickly and enhancements integrated easily into the evolving system.
Smalltalk organizes its classes into a hierarchy of classes and subclasses.
Inheritance provides a mechanism for both organizing and maintaining the collection of Smalltalk object classes. Inheritance recognizes similarities among objects, capitalizing on the fact that similar objects often behave similarly.
A subclass inherits all the methods known to the parent. If you define a new customer database class to be a type of Smalltalk SortedCollection, your application will automatically know how to add, copy, edit, remove, print and sort customer records. You need only create methods which describe the new behaviors the customer database must exhibit beyond those of the generic SortedCollection.
If a selected parent's behavior is inappropriate, you simply define a method by the same name to override the parental way of doing things. For instance, to protect confidential customer information, the print method of the CustomerRecord class could be written to perform a password checking operation before printing. The customer record would then enforce security when asked to print itself while a less rigorously defined object simply prints itself upon receipt of the same print message.
Smalltalk's inheritance features encourage "programming to exception and modification." Without inheritance, you would have to spend a good bit of your time telling new classes of objects how to do elementary things like print. And if you later revamp the procedures for printing specific data types, you would have potentially hundreds of individual print methods to update and re-compile if it were not for inheritance.
Only slight reflection is needed to appreciate the programmer productivity potential of Smalltalk's inheritance mechanism. A little more reflection will confirm that the hierarchy of Smalltalk classes is consistent with the model of classification systems we routinely lay over our perceptions of the world.
Each Smalltalk object is an encapsulated program operating on its own local data, a little self-contained computer. The user extendable Smalltalk/V system comes with over three thousand pre-defined methods in over one hundred fifty classes. With time, your personalized Smalltalk/V environment will contain hundreds, maybe thousands, of new objects, classes of objects and their associated methods.
If you had to explicitly manage program and data file handling for each Smalltalk object as well as act as traffic cop to the messaging activity, there would be no incentive to adopt object-oriented programming. The power of Smalltalk's natural human thinking model at the design level would be lost at code writing. Smalltalk/V, therefore, is designed to manage the "dirty work" of object storage and memory management for you.
Imagine the task for your hardware and operating system software if your Smalltalk/V directory were strewn with:
... and so on for hundreds or thousands of objects if it were possible.
That's what it would take if Smalltalk's objects managed themselves independently under the conventional model of computing. Smalltalk solves this problem with a global solution, an object-oriented model for storage.
The Smalltalk/V system includes two main pieces. The DLL (Dynamic Link Library) files are a collection of the shared, unchanging objects in the release system. VW.EXE is an executable snapshot of the current state of the Smalltalk/V environment, a kind of group photo preserving the state of the changeable objects in the base system, and any new objects you create. Together, VW.EXE and the DLL files comprise what we refer to as the "image."
Saving the image to permanent disk storage allows you to end a Smalltalk session, saving your objects in "suspended animation" to be revived exactly as you left them when you restart Smalltalk. Because only the VW.EXE file contains changeable objects, it is the only file that is changed when you change the image. In this global and efficient manner, Smalltalk takes care of storing objects.
Having an efficient approach to storage management might only serve to preserve chaos if RAM memory were to become cluttered with persistent though unused and unwanted objects, taking up valuable real estate in RAM if no longer needed. Smalltalk/V lets you focus on programming while automatic memory management, sometimes unglamorously referred to as "garbage collection," maximizes RAM available for the creation of new objects and keeps accumulated "clutter" from crashing the system. Automated object storage and memory management further insure a safe environment for Smalltalk application development.
By generating executable images, using multitasking and DLL resource sharing, you can run concurrent Smalltalk sessions on a single machine. Of course this can be asking for nightmares if you are trying to develop multiple applications concurrently, unless your mind is as multitasking as Windows is. This does, however, mean your end-users can enjoy efficiently running multiple Smalltalk/V applications concurrently.
This Smalltalk/V is a completely new generation of Digitalk Smalltalk software technology. Yet Smalltalk/V Windows offers code compatibility with other Smalltalk/V implementations. So while you are out on the leading edge, you don't have to lose touch with the rest of the Smalltalk/V community.
Smalltalk/V is a prescription for an exciting programming experience ... the rare combination of an open and safe system inviting you to shape its capabilities to your needs. The first several chapters of the Smalltalk/V Tutorials introduce you to the Smalltalk/V programming environment and to the range of objects and their behavior in the Smalltalk/V system.
But this is only the beginning. Smalltalk really shows its stuff in real world application development. The expanding collection of re-usable Smalltalk objects, when used in an evolutionary, prototyping development cycle, result in quick and efficient development of complex applications. The Smalltalk/V Tutorials conclude with an application development example which showcases the "design-test-improve" cycle of development encouraged by the fully object-oriented character of Smalltalk/V.