Easy coding with Smalltalk and Squeak

Small Friend


The venerable Smalltalk language is enjoying a resurgence of new interest, thanks to new implementations like the very popular Squeak.

By Randal L. Schwartz

Valeriia Samoilenko, 123RF

Why would I use Smalltalk when I'm already using its heir-apparent, Ruby?

In fact, a great resurgence in Smalltalk has occurred in the past few years, partially because of the killer app Smalltalk Seaside, a web framework. Smalltalk has the right combination of features to foster and encourage rapid development programming. (The whole agile programming and test-driven development movements were started by Smalltalk programmers.) Smalltalk is also great for metaprogramming: modifying or enhancing the language and environment for a particular set of tasks. In Ruby, this is often touted as a new feature in the form of "domain-specific languages," but Smalltalk programmers were doing that long before Ruby. Smalltalk is also more friendly, with a simple base syntax and design and powerful reflection and self-modification capabilities.

In fact at least two solid open source Smalltalk implementations are being actively developed, as well as a few commercially marketed implementations.

Simple Language

One of the things that keeps bringing me back to Smalltalk is its elegant simplicity. Everything in Smalltalk is an object. That's right, everything. Every object belongs to a class, which is in turn an object. Almost every class has a single superclass, from which objects of that class inherit methods. The exception is the Object class, which resides at the top of the hierarchy. Objects have an individual state that is held in instance variables and is managed directly by the object itself.

Variables

Variables are named with the use of alphanumeric identifiers, meaning just letters and digits. Most variables that are compound words are CamelCase, and nearly all local variables have an initial lowercase letter, such as rate or accelerationRate.

Variables start out holding the initial value of nil (a special value for this purpose). Their value can be changed by mutators, or an entirely new value can be assigned:

rate := 30
Message Sends

Unary message sends consist of just a method to invoke, with no arguments. The syntax is very simple: object on the left, method name on the right, as follows:

rate squared

This would be similar to $rate->squared in Perl or rate.squared() in Java or JavaScript. Every message send returns a value. The receiver (known as self within the method) is returned by default.

A binary message send is indicated with a symbol name made from a limited set of punctuation symbols followed by a single argument. These are typically used for traditional "math"-ish operations:

rate * time

In this case, the object rate is sent the * message with a single argument of time. Note that this is assymetrical, because the * method is looked up in the reciever's class only.

Finally, for one or more arguments, a keyword message send identifies the arguments with a colon-suffixed label:

rate raisedTo: 2.5
rate between: 5 and: 10

Because no unlabeled multi-argument messages occur, the need to "remember the parameter order," as required by other languages, has been eliminated.

Methods

A method starts with a signature, identifying whether it's a unary, binary, or keyword method. This signature is the same syntax as the message send, minus the receiver object (the first identifier), because that's implied:

squared
* aNumber
raisedTo: aNumber
between: lowNumber and: highNumber

Conventionally, the formal parameter hints at the acceptable type for the actual parameter. The signature might be followed by any number of "local variables" enclosed in vertical bars. For example, if a method needs variables count and sum to complete, you could write:

| count sum |

The method body consists of one or more message sends separated by periods. The final message send might be preceded by an up arrow (understood as "answer") to indicate that the final expression is the answered value. Thus, a complete definition of squared might be:

squared
 ^self * self.

This definition says that when I send squared to this object, it will answer the result of sending the * message to itself, with itself as the sole parameter.

Blocks

A block is similar to a method, in that it has parameters, local variables, and one or more message sends. Unlike a method, though, a block's parameters are always positional (although typically a block takes zero or only one parameter). A block is enclosed in square brackets and consists of three parts (each optional): the argument list

:arg1 :arg2 |

followed by the temporaries

| temp1 temp2 |

followed by the sequence of message sends (statements):

temp1 := arg1 doThis. temp2 := arg2 doThatWith: temp1. temp2 + temp1

Unlike the method definition, the default answer for a block is the last expression evaluated. If you include an "answer" up arrow in a block, it exits the method in which the block was defined.

Blocks are often used to define code for a callback (similar to an anonymous subroutine in Perl).

addThree := [:n | n + 3].

At this point, the code can be invoked with one parameter:

result := addTree value: 15.

This statement passes 15 in as the first parameter to the block and copies the result (18) into result.

Blocks for Control Structures

Although blocks are often used for deferring the execution of a chunk of code until later, they're also used for the control structures. For example, the common "execute this if that is true" structure is represented as:

aBoolean ifTrue: [some. code. here].

No new syntax is introduced here. This example is simply a keyword message, in which the argument is a block. This simplicity is the beauty of the Smalltalk syntax - all of the "special forms" in other languages are implemented with only what you've seen so far.

For example, an "if-then-else" is just a two-argument keyword message:

someBooleanExpression ifTrue: [true. stuff. here] ifFalse: [false. stuff. here].

For convenience, Smalltalk also defines them in reverse:

someBooleanExpression ifFalse: [false branch here] ifTrue: [true branch].

And the loops are similarly defined:

[some things. to do here. \
 something thatReturns aBoolean] \
 whileTrue. [anotherThing. \
 AbooleanExpression]\
 whileTrue: [do this. \
 before starting again].

For convenience, a whileFalse version of those loops exists. For example, suppose you want to find the smallest power of two at least as big as a given number. A simple implementation of this might be:

someNumber := 18.
powerOfTwo := 1.
[powerOfTwo < someNumber] whileTrue: [powerOfTwo := powerOfTwo * 2].

Squeak

Squeak is the most popular open source implementation of Smalltalk. A Squeak installation consists of four parts:

In general, you'll have a single VM and sources file on disk, and one or more coordinated pairs of image and changes files as you work on various projects.

The Squeak download page [1] lists the four parts. If you don't see the pre-compiled virtual machine for your architecture, the sources are also available, but they're a bit finicky for compilation. Also you'll want the SqueakV3.9.sources file for all modern images.

For a choice of images that contain your development environment and "Squeak Core," as it's called, you have two options. The simplest is the "Basic Squeak Release" (currently 3.10.2) listed on the download page, an image/changes pair from about 18 months ago (the time of the last major release). However, it has a lot of known bugs, and the development got a bit derailed. The Squeak 4.0, or even the 4.1 release, might have come out by the time you're reading this, so just follow whatever download instructions you see on the page.

Fire Up the Image

To fire up the image from your desktop environment, ensure that the VM and sources file are in the same folder and that the image and changes files are also in the same folder (which can be the same as the VM and sources, but doesn't have to be). If you drag the image file over to the VM, then Squeak should launch.

A single operating system window appears with Squeak's "desktop" within it. Squeak has its own desktop, called the World, and its own style of windows. The reason is that Squeak runs precisely cross-platform: the exact same interaction and display happens whether you're on Windows, X11, or Mac OS X, or some more exotic windowing interface. Unfortunately, this might mean that it will take a bit of time for you to become familiar with the environment, but if you've had to switch between windowing systems before, you know it's not an insurmountable task.

Mice and Colors

Squeak also uses a bit of odd terminology as far as mouse clicks are concerned. The original machines on which Smalltalk were developed had three-button mice and were colored (literally) red, yellow, and blue for the left, center, and right buttons, respectively.

The red, left, button is used for things that you usually think of as a "normal" click (or left-click). Therefore, your primary click will work pretty much as you might expect to select things and move them around.

The yellow, middle, button is used for things you think of as a "contextual" click, and it usually brings up a menu that depends on where the mouse is located. Now, this might be a right-click on your machine, or it might be a middle-click; you'll have to experiment to figure out which. And if you have only a single-button mouse, you might need to add a modifier key, such as Ctrl or Shift, to get this menu.

The blue, right, button is used as a secondary "contextual" click. In Squeak, this is used primarily to bring up a halo around on-screen widgets (called Morphs). Again, this might be a right-click or a center-click, or even a click with a modifier key in your environment.

A Space to Work

To try out some simple expressions, you can open a workspace (see Figure 1). A workspace is a simple text area in which you can type things and then execute them, either to perform an action (called a do it) or to see what value results from that action (a print it).

Figure 1: Create a workspace to try out simple expressions.

If you don't already a workspace in your world, you can left-click (red button) on the world desktop. This brings up the world menu, and near the top of the menu, you should see Workspace. When you select that item, a workspace will appear. Within this workspace, you can type an expression, such as 15 squared.

With your cursor to the right of the expression, select the contextual menu (center-click, yellow button) and find print it. (Also note the letter p by print it, which I'll get to in a moment.) When you select that, the result (225) appears immediately afterward.

To skip the contextual menu, remember the shortcut letter. If you type the shortcut letter (which might be either an uppercase or lowercase letter, so pay attention) with the right modifier key (which could be Ctrl or Opt or Alt or Cmd - you'll have to experiment to find out), the same operation is invoked.

Where Next?

In this discussion, I've just barely scratched the surface of programming with Smalltalk and Squeak, with a lot more to learn about using the image and writing code. The best source for Squeak at the moment is a "donationware" book, which is available as a free download [2]. Other resources are on the Squeak website, such as the beginners mailing list, the IRC channel, or dozens of other freely downloadable books.

INFO
[1] Squeak: http://www.squeak.org/Download/
[2] Nierstrasz, Oscar, et al. Squeak by Example. Lulu.com, 2009, http://squeakbyexample.org/