![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
This chapter has examples which need a place to hold the objects they create. Such place is created automatically as necessary; when you want to discard all the objects you stored, write an exclamation mark at the end of the statement.
Now let's create some new objects.
6.2.1 An array in Smalltalk 6.2.2 A set in Smalltalk 6.2.3 Dictionaries Getting more sophisticated, eh? 6.2.4 Closing thoughts There always ought to be some closing thoughts
An array in Smalltalk is similar to an array in any other language, although the syntax may seem peculiar at first. To create an array with room for 20 elements, do(24):
x := Array new: 20 |
The Array new: 20
creates the array; the x :=
part
connects the name x
with the object. Until you assign
something else to x
, you can refer to this array by the name
x
. Changing elements of the array is not done using the
:=
operator; this operator is used only to bind names to
objects. In fact, you never modify data structures;
instead, you send a message to the object, and it will modify itself.
For instance:
x at: 1 |
nil |
The slots of an array are initially set to "nothing" (which
Smalltalk calls nil
). Let's set the first slot to the
number 99:
x at: 1 put: 99 |
x at: 1 |
99 |
These examples show how to manipulate an array. They also show the standard way in which messages are passed arguments ments. In most cases, if a message takes an argument, its name will end with `:'.(25)
So when we said x at: 1
we were sending a message to whatever
object was currently bound to x
with an argument of 1. For an
array, this results in the first slot of the array being returned.
The second operation, x at: 1 put: 99
is a message
with two arguments. It tells the array to place the second
argument (99) in the slot specified by the first (1). Thus,
when we re-examine the first slot, it does indeed now
contain 99.
There is a shorthand for describing the messages you
send to objects. You just run the message names together.
So we would say that our array accepts both the at:
and
at:put:
messages.
There is quite a bit of sanity checking built into an array. The request
6 at: 1 |
x at: 21 |
Finally, note that the object stored in an array is just like any other object, so we can do things like:
(x at: 1) + 1 |
We're done with the array we've been using, so we'll
assign something new to our x
variable. Note that we
don't need to do anything special about the old array: the
fact that nobody is using it any more will be automatically
detected, and the memory reclaimed. This is known as garbage collection
and it is generally done when Smalltalk finds that it is
running low on memory. So, to get our new object, simply do:
x := Set new |
x |
The kind of object is printed out (i.e., Set
), and then the
members are listed within parenthesis. Since it's empty, we
see:
Set () |
Now let's toss some stuff into it. We'll add the numbers 5
and 7, plus the string 'foo'. This is also the first example
where we're using more than one statement, and thus a good place to present
the statement separator--the .
period:
x add: 5. x add: 7. x add: 'foo' |
Like Pascal, and unlike C, statements are separated rather than
terminated. Thus you need only use a .
when you have finished
one statement and are starting another. This is why our last statement,
^r
, does not have a .
following. Once again like Pascal,
however, Smalltalk won't complain if your enter a spurious
statement separator after the last statement.
However, we can save a little typing by using a Smalltalk shorthand:
x add: 5; add: 7; add: 'foo' |
This line does exactly what the previous one did.
The trick is that the semicolon operator causes
the message to be sent to the same object as the last message
sent. So saying ; add: 7
is the same as saying
x add: 7
, because x
was the last thing a message was sent
to.
This may not seem like such a big savings, but compare
the ease when your variable is named aVeryLongVariableName
instead of just x
! We'll revisit some other occasions
where ;
saves you trouble, but for now let's continue with
our set. Type either version of the example, and make sure
that we've added 5, 7, and "foo":
x |
we'll see that it now contains our data:
Set ('foo' 5 7) |
What if we add something twice? No problem--it just stays in the set. So a set is like a big checklist--either it's in there, or it isn't. To wit:
x add:5; add: 5; add: 5; add: 5; yourself |
We've added 5 several times, but when we printed our set back out, we just see:
Set ('foo' 5 7) |
yourself
is commonly sent at the end of the cascade,
if what you are interested in is the object itself--in this
case, we were not interested in the return value of add: 5
,
which happens to be 5
simply. There's nothing magic in
yourself
; it is a unary message like printNl
,
which does nothing but returning the object itself. So you
can do this too:
x yourself |
What you put into a set with add:
, you can take out
with remove:
. Try:
x remove: 5 x printNl |
The set now prints as:
Set ('foo' 7) |
The "5" is indeed gone from the set.
We'll finish up with one more of the many things you can do with a set--checking for membership. Try:
x includes: 7 x includes: 5 |
From which we see that x does indeed contain 7, but not 5.
Notice that the answer is printed as true
or false
.
Once again, the thing returned is an object--in this case, an
object known as a boolean. We'll look at the use of
booleans later, but for now we'll just say that booleans are
nothing more than objects which can only either be true or
false--nothing else. So they're very useful for answers to
yes or no questions, like the ones we just posed. Let's
take a look at just one more kind of data structure:
A dictionary is a special kind of collection. With a regular array, you must index it with integers. With dictionaries, you can index it with any object at all. Dictionaries thus provide a very powerful way of correlating one piece of information to another. Their only downside is that they are somewhat less efficient than simple arrays. Try the following:
y := Dictionary new y at: 'One' put: 1 y at: 'Two' put: 2 y at: 1 put: 'One' y at: 2 put: 'Two' |
This fills our dictionary in with some data. The data is
actually stored in pairs of key and value (the key is what
you give to at:
---it specifies a slot; the value is what is
actually stored at that slot). Notice how we were able to
specify not only integers but also strings as both the key
and the value. In fact, we can use any kind of object we
want as either--the dictionary doesn't care.
Now we can map each key to a value:
y at: 1 y at: 'Two' |
which prints respectively:
'One' 2 |
We can also ask a dictionary to print itself:
y |
which prints:
Dictionary (1->'One' 2->'Two' 'One'->1 'Two'->2 ) |
where the first member of each pair is the key, and the second the value. It is now time to take a final look at the objects we have created, and send them to oblivion:
y x! |
The exclamation mark deleted GNU Smalltalk's knowledge of both
variables. Asking for them again will return just nil
.
You've seen how Smalltalk provides you with some very powerful data structures. You've also seen how Smalltalk itself uses these same facilities to implement the language. But this is only the tip of the iceberg--Smalltalk is much more than a collection of "neat" facilities to use. The objects and methods which are automatically available are only the beginning of the foundation on which you build your programs--Smalltalk allows you to add your own objects and methods into the system, and then use them along with everything else. The art of programming in Smalltalk is the art of looking at your problems in terms of objects, using the existing object types to good effect, and enhancing Smalltalk with new types of objects. Now that you've been exposed to the basics of Smalltalk manipulation, we can begin to look at this object-oriented technique of programming.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |