The Smalltalk Language
Last updated at 7:22 am UTC on 8 November 2006
This is chapter 2 of the Squeak Tutorial
< previous chapter | next chapter >
Doing some simple things in Smalltalk
Smalltalk is a highly dynamic language, you can often see the results directly. Let's open a Workspace window to start playing around: Open the world menu, then click on "open", then "Workspace". In a workspace, you can execute small programs, and mix that with comments and results.
Let's see how Smalltalk computes. Type this into the workspace:
2 + 2
Now run the code:
- Select it with the mouse
- Print the result: right click on the selection, and choose "Print it"
- You an guess what the expected result is, can't you?
You actually executed a small program! This works not only in a workspace but nearly everywhere in Smalltalk where you can edit some text: see a small snippet of code, select it, "print it" (keyboard shortcut: cmd-p) and look at the result.
Now for something more interesting:
100 factorial
Type (or copy) this into a new line, select it and "Print it". You see the factorial of 100, i.e. the product 1 * 2 * 3 * ... * 99 * 100. As you can see, Smalltalk has no problems with handling large numbers.
Printing
27 / 6
gives (9/2), a fraction. Fractions are just another kind of numbers available in Smalltalk.
One of the Smalltalk maxims is "Everything is an object". You've seen some numbers, they are objects of course. But there are also window objects, text objects, rectangles, dates. So let's see some graphical objects. Type (or copy) this:
EllipseMorph new openInHand
and then select it, right click and choose "Do it". A yellow ellipse appears under your mouse pointer, you can move it across the screen. Click once to put it somewhere. You can later pick it up with the mouse and put it anywhere you like. The yellow ellipse is an example of a Morph, a graphical object that can react to mouse clicks, change its appearance, contain other morphs, and be scripted.
The Object Universe
Smalltalk lets you think about your program in terms of objects. Objects collaborate to solve your problem, they can "talk" to each other to make things happen. It turns out that it is very natural to model a problem and its solution in terms of communicating objects, because that is close to our natural way of thinking. The Smalltalk system is full of objects, and you have created yourself a few new ones in the previous examples. For example, 27 is an integer object, and executing 27 / 6 creates a new fraction object, 9/2.
Objects communicate by sending each other messages. When an object receives a message, it will decide what to do. It may change its state (like a window that closes itself) and / or return an answer which is another object. Let's look at our example, EllipseMorph new openInHand again, and interpret this in terms of objects and messages. EllipseMorph is a class object, that means it can create new objects and describes how they react to messages. EllipseMorph new sends the message new to the EllipseMorph class. The class creates a new EllipseMorph, and answers that. The new morph is still invisible. By sending our newborn EllipseMorph the message openInHand we make it appear under the mouse pointer. Now every time we move the mouse, the ellipse morph is sent a notification message and reacts by placing itself at the new mouse position. When we click, another message is sent to the ellipse morph that makes it stop following the mouse.
These reactions to mouse clicks and mouse moves are part of the ellipse morphs behaviour, all ellipse morphs react in the same way. The behaviour is specified by the EllipseMorph class object, if you wanted to find out how this is programmed, you would start by looking into the code of the EllipseMorph class.
Let us send some messages to a new ellipse morph. Execute ("Do it") the following line:
ball := EllipseMorph new openInHand
Now we have created a new ellipse object and given it the name "ball". From now on we can refer to it by that name. Let's ask our ball for its position. Print ("Print it" , cmd-p) this:
ball center
The answer is printed right next to the code, for me it is 876@233. We send the message center to the ball, and it responds with a point object (the x@y-notation is used for point objects). Now pick up the ball and move it somewhere else. Can you see how its center changes?
Let's give the ball a drop shadow:
ball addDropShadow
This message changes the appearance of the morph. In more general terms, the state of the object is changed in response to the message.
Move it to the left margin of the screen:
ball left: 50
This message is a bit more complicated. It tells the morph to put its left bound at the coordinate 50. left: 50 is a message with an argument, the integer 50. Again the state (the position) of the object is changed.
Change its color
ball color: Color random
These are two messages. Color random creates a new random color object which is then used as an argument when sending ball the color: message. In more detail: Color random means we send the message random to the class object Color. Color knows how to respond: it creates three random numbers and uses these as values for hue, saturation, and brightness of a new color object. Finally, it returns the new color object.
Congratulations! You have created new objects and changed them by sending them messages. Before we show you more interesting things we'll tell you about the syntax of Smalltalk, so you can read programs easily.
All the syntax in one short Smalltalk Program
Smalltalk is a very simple language, and nearly all of its syntax can be shown in a single example. Open the Transcript window (World menu / Open / Transcript). The Transcript window shows basic systems messages and it is a place where you can print your own messages.
Copy and paste this program into a Workspace: (World menu / open / Workspace) (How?)
"Prints the integers between 1 and 10, and a string stating whether each is even or odd"
1 to: 10 do: [:n |
n even ifTrue: [
Transcript show: n; show: ' is even'; cr]
ifFalse: [
Transcript show: n; show: ' is odd'; cr]
]
Now run the code:
- Select it (cmd-a to select all)
- Run the selection (cmd-d. d is for "Do it")
You should see a printout of the numbers 1 through 10 and whether each is odd or even. This short example demonstrates nearly all of the language features of Smalltalk. Let us disect it from the inside out:
Objects and Messages
Here are some of the objects used in the example:
- 1 is an Integer object
- 10 is an Integer object
- ' is even' is a String object
- Transcript is a TranscriptStream object. It recieves text and displays it in a window
- [ ... ] is a BlockClosure object. It holds executable code.
Here are some of the messages:
- Transcript show: n.
- Transcript cr.
- 1 to: 10 do: [ ... ].
'Sending a message' means the same thing as 'Calling a method' in other languages. There are three types of messages in Smalltalk:
- Unary message sends, such as
Transcript cr.
In this example, we send the message 'cr' to the 'Transcript' object. This message means 'begin a new line'. Unary methods do not take parameters.
- Binary message sends, such as,
1 + 2.
'1' is the recipiant of the message, '+' is the message, and '2' is the arguement. Binary methods take exactly one parameter. (there are none of these in the example)
- Keyword message sends. These are the most generally useful, and the only type that can recieve multiple parameters. Examples:
Notes about message syntax
- Unary and Binary messages can be immediately followed by another message send. For instance:
n even ifTrue: [ ... ] ifFalse: [ ... ]
is a unary message (even) followed by a keyword message (ifTrue:ifFalse:). 'n even' returns a Boolean object which is then sent the message ifTrue:ifFalse:. This message will be explained shortly.
- Multiple messages to a single object are separated by semicolens (;). For example:
Transcript show: n; show ' is even'; cr
is three message sends to the same object (Transcript)
- Message sends to different objects are separated by a period (.). For example:
Transcript show: n.
Transcript show: ' is even'.
Transcript cr.
is a longer way to send three messages to Transcript.
Blocks
Smalltalk and Ruby are the only two languages that have the concept of a block. A block is an object that contains executable Smalltalk code. It is, at once, an object and code. It is very similar to lambda forms in Lisp. This means:
- You can pass a block of code around in message sends
- you can choose to run the block or not.
Thus flow control, which is a language construct in many languages, can be implemented as a message send in Smalltalk.
Here is the code to find the maximum of two integers, first in C, then in Smalltalk. First C:
if (a > b) max = a;
else max = b;
Now in Smalltalk:
a > b ifTrue: [ max := a ]
ifFalse: [ max := b ]
In C, the if ... else construct is built into the language; In Smalltalk, ifTrue:ifFalse: is just a message send, like any other action. This functionality is made possible by Blocks.
There are two types of blocks in Smalltalk:
- Blocks without parameters. The syntax is:
[ ... ]
- Blocks with parameters. Syntax:
[ :a :b :c | ... ]
. a, b, and c are the parameters
Examining the simple program
You now have all the understanding you need to understand the simple example:
"Prints the integers between 1 and 10, and a string stating whether each is even or odd"
1 to: 10 do: [:n |
n even ifTrue: [
Transcript show: n; show: ' is even'; cr]
ifFalse: [
Transcript show: n; show: ' is odd'; cr]
]
Let us examine it line by line:
Summary
- All Smalltalk programming is done by sending messages between objects
- There are three types of messages
- Blocks are objects that contain executable code
- ifTrue:ifFalse: is used for flow control
- apostrophes surround strings
- double-quotes surround comments
For a quick reference card on this and other Squeak coding, see the Terse guide to Squeak
Move this to the browsers and classes chapter
Each has a typical use in Smalltalk:
- Unary messages are used to give very simple instructions to an object.
- Binary messages are used for messages that are, in some sense, commutative. That is, it is symantically correct for either object to be the recipiant
- Keyword messages are used for everything else. An advantage that keyword messages have over function names is that their name is a very clear indication of their usage, and what each parameter should be. It also saves programmers from the hassle of creating yet another meaningless name; since each message has unique parameters and a unique function, that automatically translates to a unique name in Smalltalk's syntax.