Hints on Smalltalk Style

Here are a few suggestions on writing Smalltalk programs with good style. These are by no means comprehensive!

As in any programming language, include useful comments and use descriptive variable names. Since Smalltalk doesn't include type declarations, some programmers like to use names such as anArray or aStream for variables to give a hint as to what kind of object is expected. This has no significance for the Smalltalk compiler, though.

Use indentation consistently in your methods. Make methods short -- typically two browser panes worth of text at most. (Generally the style in Smalltalk is to make methods shorter than the typical C or C++ procedure.) If you do end up with a method that keeps getting longer and longer, define some private auxiliary methods, and then just invoke then using (for example) self helperMethod.

Instance variable, argument, and temporary names should start with a lower-case letter; global and class variables with an upper-case letter. Unfortunately, underscore isn't a legal part of identifiers in Smalltalk, so use capitalization to separate words, e.g. aVeryLongInstanceVarName.

It is almost always a mistake to write code that tests for the class of an object. For example, in your pinball game, don't write something like

x class = Flipper ifTrue: [...].
x class = BlackHole ifTrue: [...].
Instead, turn this around and send a message to x so that flippers and black holes can respond differently:
x hitBy: self
If you really need to know whether an object obeys some message protocol, define a method to ask. For example, all objects in Smalltalk understand isNumber. Numbers return true, everything else returns false.

Unfortunately the syntax for conditionals in Smalltalk makes nested conditionals hard to read. You can judiciously use ^ (return) to improve readibility. Consider the sign method for Numbers, which returns -1, 0, or 1 depending on whether the number is negative, zero, or positive.

Here is a version using nested conditionals:

sign
   ^ self < 0 
      ifTrue: [-1] 
      ifFalse: [self > 0 ifTrue: [1] ifFalse: [0]]
Compare with:
sign
   self < 0 ifTrue: [^ -1].
   self > 0 ifTrue: [^ 1].
   ^ 0
The sign method isn't too bad, but it gets worse with more complicated logic. Sometimes it's worth writing an auxiliary method just so you can return from the middle of the auxiliary method to make the code clearer. (Remember ^ pops out of nested loops, conditionals, etc.)

Generally, avoid referencing global variables, except for class names. (Smalltalk Express doesn't always follow this rule ... for example ClrBlue is a global variable. In e.g. OTI Smalltalk, you achieve this effect by writing Color blue. Often it's more appropriate to use self or a message to a class in place of a global variable. Here's a questionable example from the Smalltalk haikus the 505 students wrote the other year:

i ride a turtle
into object nirvana
evan become: nil
A haiku in better Smalltalk style would have been:
i ride a turtle 
into object nirvana
self become: nil