oreilly.comSafari Books Online.Conferences.


Smalltalk for Everyone Else

by Keith Fieldhouse

You've decided to expand your horizons. You've been programming exclusively in Java (or C++, or Perl, or Ruby) for a while now. You're happy and productive, but you have this nagging feeling that you're solving problems by rote rather than thinking as creatively as you once did. Learning a new language, especially one that forces you to re-examine some of your notions about software development, may be just the ticket.

Smalltalk, an influential language with deep roots in software development practice, offers an outstanding opportunity for stretching your mind and exercising your development muscles. The only drawback is that once you try it, you may never go back. This article will help you get started.

Researchers at Xerox's legendary Palo Alto Research Center developed Smalltalk more than 30 years ago. It took the shape that it largely still holds today with the release of Smalltalk-80 in 1980. Xerox provided the ST-80 release to a small number of companies at the time, including Apple Computer. Years later, when Alan Kay and Dan Ingalls (the architect and lead developer of Smalltalk at PARC) were at Apple, they wanted a system with which they could develop multimedia educational software. They took the original Smalltalk-80 implementation at Apple and developed a modern implementation called Squeak. The paper "Back to the Future: The Story of Squeak, A Practical Smalltalk Written in Itself" details the whole story of Squeak's development.

Despite (or perhaps, because of) its long history, Smalltalk remains extremely influential and relevant today. The authors of the seminal Design Patterns were steeped in Smalltalk development practice. The originators of eXtreme Programming developed their teachings during large-scale Smalltalk development projects. Seaside, a continuation-based web development framework for Smalltalk, has received some positive attention, as has DabbleDB a Web 2.0 application written in it. On the desktop, the OpenCroquet project provides an immersive, peer-to-peer collaboration architecture/application framework.

You can obtain Squeak for a variety of platforms at the Squeak website. Linux users can often find Squeak in the repositories for their distributions. For example, Ubuntu users can simply apt-get install squeak as long as the Ubuntu "Multiverse" is in /etc/apt/sources.lst.

The Smalltalk Language

Before I talk about at the mechanics of using Squeak, I need to explain the Smalltalk language itself. In Smalltalk, everything is an object. Nearly every action in Smalltalk involves sending a message to an object. As may make sense for a language that is heavily message-oriented, there are plenty of ways to send a message.

Unary messages have no arguments. For example, if a is an array:

a reverse.

returns an array arranged in the reverse order of the receiver, a.

Arithmetic operators are really binary messages. + is a typical example:

5 + 4.

This sends the + message to the 5 object (which is an instance of the SmallInteger class). The implementation of the + message receives the SmallInteger 4 as its only argument and returns the sum of the two numbers.

Finally there are keyword messages. These accept arguments that are separated and identified by keywords. For example, you can call the at:put: method of a Dictionary object like this:

d at: 'Fred' put: 7.

This inserts the value 7 in the Dictionary d at key Fred. Careful selection of the keywords used to identify a particular method can greatly enhance code readability.

Precedence is straightforward: evaluation occurs left to right. Unary messages get sent before binary messages, and binary messages come before keyword messages. You can use parentheses to alter precedence.

There's a subtle implication of these rules: addition is simply a message send represented by sending the + binary message to objects like SmallInteger instances that understand it. Given these precedence rules, the Smalltalk statement

2 + 3 * 3.

evaluates to 15, not 11, because of the left-to-right evaluation of message sends.

The assignment message is :=. The statement terminator is a period. You can send successive messages to the same object by separating them with a semicolon. The pipe character (|) marks the declaration of local variables in a method. The caret (^) returns a value from a method, and double quotes enclose comments.

Here's an example that ties some of this together:

    "Class side method to initialize a dayname->ordinal day number
     mapping singleton"
    | map |
    map := Dictionary new.
    map at: 'Sunday' put 0;
        at: 'Monday' put 1;
        at: 'Tuesday' put 2;
        at: 'Wednesday' put 3;
        at: 'Thursday' put 4;
        at: 'Friday' put 5;
        at: 'Saturday' put 6.

Naming this method with a my prefix follows the convention that such methods are for the private use of an object, though the language does not enforce this. The initial comment describes this method as a "class-side" method, which is the Smalltalk way of describing what might be more familiar to you as a static method. This code declares map, a variable local to the scope of the method. It initializes the variable as a Dictionary object and sends it a series of at:put: messages. Finally, the method returns the new, initialized dictionary.

That's about it for Smalltalk syntax. You may have noticed that there has been no discussion of control keywords such as if or while. In Smalltalk, there are none. Rather, the class library implements classes that understand messages that serve roughly the same purpose. For example, to assign the value 7 to the variable a, if a is less than the current value of b, write:

(a < b) ifTrue: [ a := 7 ].

The < operator is a unary message sent to the a object; it returns an instance of False or True (subclasses of Boolean) based on evaluating b against a. A Boolean instance understands the ifTrue: message, which takes a block closure as its argument (the code surrounded by []). A block closure is a fragment of Smalltalk that you can store and execute at a later time. An instance of False ignores the block sent with ifTrue:, an instance of True executes it.

Pages: 1, 2, 3

Next Pagearrow

Sponsored by: