Small World: A Little (More) Smalltalk

Lesson 1: Just Browsing

When you begin the Small World system you will be presented with an application window, which looks like the following:

Click the button marked Class Browser, and you should get a window that looks something like the following:

The exact appearence of the window is determined by your operating system, and may not be exactly as shown here. The class browser is the fundamental tool used to explore the Small World system. In the simplest, it is used for evaluating expressions. Try entering the expression 2 + 3 in the text line at the top of the window and hitting the button marked evaluate expression. The result should appear in the centeral pane, as follows:

Integers are just one of several literal values in the Smalltalk world. Other types of literals include real numbers (such as 3.14), characters, strings and booleans. The notation for character literals is the dollar sign followed by the character text. Try typing the expression:

   $a isLowerCase

String literals are formed using the single quote mark. Strings can be catenated together using the addition symbol. Try entering the expression:

   'hello' + 'world'

Booleans are represented by the two constants true and false. You have seen a boolean result already as the response to the message isLowerCase.

There is another more unusual literal value you will soon encounter. The value nil is used for a variety of purposes, for example to represent an otherwise undefined variable.

Comments in Smalltalk are written between double quote marks. Comments are used to provide documentation for the system, but are otherwise ignored.  Try evaluating the expression

  2 " comment here " + "and another" 7 "and finally, another"

You can use the button marked clear to clear the two text areas.

Messages

Computation in Smalltalk occurs in response to messages. A message is a request given to an object asking it to perform an action. The receiver for the message is always written first. There are three forms of messages in Smalltalk. A unary message is a word. The the message abs, for example, requests the computation of the absolute value of a number.  Try entering the expression -4 abs. A binary message is a symbol, such as the plus sign. You have seen an example of this in the earlier expression 2+3. Technically, the value to the left of the symbol is the receiver for the message, and the value to the right is considered an argument; that is, an additional value used in the execution of the message. The third type of message is a keyword message. A keyword message is written as a series of words followed by colons. After each colon is an argument value. A simple keyword message is between:and:, which tests a value to see if it is between two endpoints.  Try entering the expression:

  5 between: 0 and: 10

This message also works with characters, strings, and real numbers.  Try the following:

  $c between: $a and: $z
  3.7 between: 2.5 and: 4.8
  'ben' between: 'alice' and: 'chris'

There is a precedence among messages. Unary messages bind most tightly, followed by binary messages, and finally keyword messages. Try entering the following:

  -1 + 7 between:  -3 abs and: 5 + 2

The expression -1 + 7 will be evaluated first, yielding 6. Next the expression -3 abs will be evaluated, which returns 3.  This is followed by 5+2, which returns 7. Finally the expression 6 between: 3 and: 7 will be executed, which will return true.

Parenthesis can be used for grouping complex messages in order to make them easier to read, or when the precedence rules should not be followed. Try comparing the expressions (4 - 6) abs and 4 - 6 abs, for example. (Make sure you leave a space after the minus sign, otherwise the parser thinks you mean the negative number -6, and not the binary operator).

The following illustrate a few of the example messages that can be evaluated by the Small World system. Try executing each and examining the result:

2*3 'abc' < 'abce' 'be here how' find: 'here'
2/3 'abc' at: 2 true not
2@3 'be here now' break 7 respondsTo: '+'
3 rem: 2 '2 + 3' doIt 12 random
3 quo: 2 Window notify: 'how odd' 12 random

Classes

All objects in the Smalltalk universe are instances of a class. A class is a grouping of objects with similar behavior. You can discover the class of an object by sending it the message class.  Try entering the expression

  'abc' class

You should get the expected response String. Try discovering the class of other literals, such as $c, 3.14, true, and nil. Now print the class of an integer, such as 7. You will find that the class of 7 is SmallInt. This stands for Small Integer, and represents the class of values smaller than 232. Try comparing

  (255*255*255*100) class

and

   (255*255*255*200) class

The latter should indicate that the expression is an instance of LargePositive, which represents large positive integers. Smalltalk can represent integers of arbitrary size.

You can explore classes and the operations they support using a class editor. Try selecting the class Char in the list of classes on the right hand side of the smalltalk browser. If necessary, you can use the scroll bar to move up and down the list of classes. Then press the button marked examine class. You should get a window that looks something like the following:

The list on the right side represents some of the messages that instance of the class Char understand. Some of these, such as isLowerCase, you have seen already. Other ones will be new. You can try evaluating expressions using these messages in the Smalltalk browswer. Explore the range of messages for some of the other classes, such as String or SmallInt. You can dismiss a class editor window by pressing the close button.

Were you surprized at the result of evaluating the expression 2/3? What is the type (class) of this value? What about 2@3?  Whare are some of the operations recognized by the classes Fraction or Point ?

Classes and Metaclasses

The value 7 is an instance of the class SmallInt. But SmallInt is itself an object. You can send messages to SmallInt, just as you can send messages to 7. What is the class of SmallInt? The answer is that it is an instance of Meta-SmallInt. You can see the information associated with the metaclass by pressing the button marked examine metaclass in a class editor.

The idea of a metaclass is used mostly for initialization of new values. An instance of a class is normally created by the message new. Try evaluating the expression:

   True new

You will see that the result is, as you expect, the value true. Later, after we have explained methods, try finding the method for new in the metaclass for True.

Inheritance

We often form abstract categories to describe objects in the "real world". For example, a Cat is a Mammal which is an Animal which is in turn a Living Thing. These abstractions allow us to attach information at an appropriate level of abstraction, for example we know that all Mammals have hair, and that all Animals breath oxygen. The same type of organization is used for Smalltalk classes. A character, for example, is considered to be a special form of Magnitude, an abstract category for things that can be compared to each other. We say that Magnitude is a superclass of Char, and that Char is in turn a subclass of Magnitude. Other things that are magnatudes include numbers and strings. The class Magnitude is a subclass of Object, which is an ancestor class for all values in the Smalltalk universe. (Some people prefer the terms parent class and child class for superclass and subclass).

As a practical matter, what the superclass/subclass relationship means is that all methods defined in class Magnitude are also applicable to instances of subclasses, such as Char and Integer.  This is termed inheritance. We say that the class Char inherits the methods from class Magnitude, which in turn inherits from class Object. Inheritance also applies to instance variables, which we will describe shortly. That is, instance variables defined in a superclass are also accessible within a subclass.

It is possible for a subclass to have a method with the same name as one in the parent class. In this case we say that the method in the subclass overrides the superclass. We will see examples of this in later lessons.

There are two ways to view the inheritance hierarchy. One way is to evaluate the following expression

   Object hierarchy

The result will be a printable representation of the hierarchy for all classes in the Small World, where inheritance is indicated by indentation. The result is something like the following:

The message hierarchy is understood by any class, not just Object. You can find the subclasses of any class using this message. For example, the expression Integer hierarchy will produce just the portion of the class hierarchy rooted at the class Integer.

Another way to view the class hierarchy is to press the button marked examine superclass in the class editor. The result should be a class editor for the parent class. Try tracing the class hierarchy for Char in this fashion. You can dismiss the class editor windows by pressing the button marked close.

Methods

When an object accepts a message it executes a series of actions that are known as a method. You can view methods by selecting the message name in the class browser. Try selecting the method isLowerCase in the class Char.  The class browser should then look something like the following:

If necessary you can resize the window by dragging the lower right hand corner, or alternatively you can use the scroll bars to view large methods. When the message isLowerCase is presented to an instance of class Char this is the statement that will be executed.  Methods have a very simple form, which can be desribed as follows:
 
  heading    | optional temporary variables |
       body


The heading includes the message signature, as well as the names associated with any argument values.  If there are any temporary variables needed for this method they are written between a pair of vertical bars.  We will have more to say about variables in a moment. The body of a method consists of a series of Smalltalk statements. A period is used to separate statements, just as in English. Use class editors to examine a variety of methods, and notice how they all have this similar form. During your explorations you will undoubtedly encounter some types of expressions you do not yet understand, but which will be explained in the next few sections.

Statements

The body of a method is composed of one or more statements. There are only three types of statements in Smalltalk. The simplest is an expression statement. An expression is evaluated, and whatever result it produces (often only nil) is simply thrown away. An expression statement is normally executed for a side effect, for some other purpose other than the result. A second type of statement is an assignment statement. This is used to evaluate and expression and change the value of a variable. The assignment operator is written as a two character sequence <-. An example might be something like

   x <- 3 + 4

The third type of statement is a return statement. The return statement ends a method, and indicates a value to be returned to the originator of the message. The return operator is the up arrow, ^. A typical return statement might be

  ^ 'yeah baby'

As noted earlier, periods are used as statement separators or terminators. It is not necessary to have a period following the last statement in a method (or in a block, which we will describe shortly).

Traditional control flow statements are handled in a slightly unusual fashion in Smalltalk. They are actually special cases of expressions. For example, consider the conditional statement. Try executing the following statement and examine the result:

  (3 < 7) ifTrue: ['happy'] ifFalse: ['sad']

The way this statement is executed is that the receiver is first determined, and then a message is given to that recieiver. In this case the reciever is the result of the expression (3 < 7), which evaluates to the boolen value true. The message ifTrue:ifFalse: is given to the value true. This message evaluates its first argument, and ignores its second. (You can see the body of this method in the class True, as well as the corresponding method in class False, using the class editor).

The square brackets are used to create a block. A block is a way to bundle up a series of statements and hold them until you want them to be executed. In a certain sense a block is like a method: is encloses a series of statements, and as we will see later, it can even take arguments. Blocks are used for a conditional because we want to execute either the true part or the false part, but not both. Compare, for instance, the execution of the above statement to the following expression that has the same superficial form:

  (3+7) between: (2+3) and: (5 + 10)

Because the latter expression uses parenthesis, the expressions 2+3 and 5+10 will be evaluated before the message between:and. The ifTrue:ifFalse: message, on the other hand, uses blocks and hence the evaluation of the arguments is delayed until after the result of the receiving expression is known.

Blocks are also used in the formation of loops. The following is a typical while loop (the use of variables, such as those shown here, will be discussed shortly):

   [ i > 0] whileTrue: [ j <- j + i. i <- i - 1]

Notice that blocks are used for both the conditional and the body of the loop.

Blocks can have arguments. These are used in certain situations. For example, consider the following loop used to compute the sum of the values from 1 to 10:

sum <- 0.
1 to: 10 do: [:i | sum <- sum + i]


The argument to the block is written as an identifier with a preceding colon. There can be any number of block arguments, which must be followed by a vertical bar. The remainder of the block is then written after the bar. In this case, the statement will create a loop in which the variable i will take on the values from 1 to 10. The body of the loop then forms the sum of these integers.

Variables

A variable is a name that can be attached to a value. Smalltalk is a dynamically typed language. This means that types (that is, classes) are associated with values, and not variables. A variable can at one point in time be holding an integer, and at another point be holding a string or a character or some other value.  In Small World there are five varieties of variables:
In order to illustrate the use of the latter three categories we first have to show how to create a class.  This will be illustrated in the next lesson.

Primitive Operations and Arrays

In browsing methods in the Small World you will sometimes run across expressions such as the following:

   ^ <34 self arg> " add ourself and the argument "

The expression between the angle brackets is termed a primitive operation. A primitive operation is something that cannot be handled in Smalltalk, and is therefore processed by the underlying virtual machine. There are about 100 primitive operations in the Small World system. These will be described in the section of the book devoted to the Small World virtual machine.

Another type of expression you may encounter looks like the following:

   #( (2+3) 'foo' (Pane image: img))

This is termed an array expression. An array is a block of memory values accessed by their index locations. An array is normally created by the message new: with an argument that indicates the number of elements in the array. Each position must then be filled with a value, as in the following sequence:

   t <- Array new: 3.
   t at: 1 put: 'hello'.
   t at: 2 put: 'new'.

   t at: 3 put: 'world'.

This entire sequence can be shortened by using an array expression:

   t <- #( 'hello' 'new' 'world' )

Next

Common Errors

Q: I tried evaluating an expression and I get an error window for an Unrecognized message selector. Why?
A: There are several possible reasons. You might have mistyped the name of a message selector. You might have left the colon off a keyword message. You might have misunderstood the precedence involved in an expression and left out a set of parentheses. Close the window, fix the error, and try again.

Q: I tried evaluating 7 < 'abc' and got an unrecognized message selector window.
A: Yes, and is an apple less than or greater than an orange?  Numbers and strings don't mix, and don't speak the same language.

Q: I was messsing around and accidently pressed the delete class button. Have I destroyed everything?
A: Only if you then pressed the save image button. Otherwise, just quit the Small World application without saving the image, and then restart the system. While you are outside of the Small World application you might think about making a backup copy of the image file, just in case.