forked from bonzini/smalltalk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tutorial.texi
3916 lines (3364 loc) · 138 KB
/
tutorial.texi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
@table @b
@item What this manual presents
This document provides a tutorial introduction to the Smalltalk language
in general, and the @gst{} implementation in particular.
It does not provide exhaustive coverage of every feature of the language
and its libraries; instead, it attempts to introduce a critical mass of
ideas and techniques to get the Smalltalk novice moving in the
right direction.
@item Who this manual is written for
This manual assumes that the reader is acquainted with
the basics of computer science, and has reasonable proficiency
with a procedural language such as C. It also assumes that the reader
is already familiar with the usual janitorial tasks associated with
programming: editing, moving files, and so forth.
@end table
@menu
* Getting started:: Starting to explore @gst{}
* Some classes:: Using some of the Smalltalk classes
* The hierarchy:: The Smalltalk class hierarchy
* Creating classes:: Creating a new class of objects
* Creating subclasses:: Adding subclasses to another class
* Code blocks (I):: Control structures in Smalltalk
* Code blocks (II):: Guess what? More control structures
* Debugging:: Things go bad in Smalltalk too!
* More subclassing:: Coexisting in the class hierarchy
* Streams:: A powerful abstraction useful in scripts
* Exception handling:: More sophisticated error handling
* Behind the scenes:: Some nice stuff from the Smalltalk innards
* And now:: Some final words
* The syntax:: For the most die-hard computer scientists
@end menu
@node Getting started
@section Getting started
@menu
* Starting Smalltalk:: Starting up Smalltalk
* Saying hello:: Saying hello
* What happened:: But how does it say hello?
* Doing math:: Smalltalk too can do it!
* Math in Smalltalk:: But in a peculiar way of course...
@end menu
@node Starting Smalltalk
@subsection Starting up Smalltalk
Assuming that @gst{} has been installed on your
system, starting it is as simple as:
@example
@b{$} gst
@end example
the system loads in Smalltalk, and displays a startup banner
like:
@display
GNU Smalltalk ready
st>
@end display
You are now ready to try your hand at Smalltalk! By the
way, when you're ready to quit, you exit Smalltalk by typing
@kbd{control-D} on an empty line.
@node Saying hello
@subsection Saying hello
An initial exercise is to make Smalltalk say ``hello'' to
you. Type in the following line (@code{printNl} is a upper case
N and a lower case L):
@example
'Hello, world' printNl
@end example
The system then prints back 'Hello, world' to you. It prints it
twice, the first time because you asked to print and the second
time because the snipped evaluated to the 'Hello, world' string.@footnote{
You can also have the system print out a lot of statistics which
provide information on the performance of the underlying Smalltalk
engine. You can enable them by starting Smalltalk as:
@example
@b{$} gst -V
@end example
}
@node What happened
@subsection What actually happened
The front-line Smalltalk interpreter gathers all text
until a '!' character and executes it. So the actual
Smalltalk code executed was:
@example
'Hello, world' printNl
@end example
This code does two things. First, it creates an object of
type @code{String} which contains the characters ``Hello, world''.
Second, it sends the message named @code{printNl} to the object.
When the object is done processing the message, the code is
done and we get our prompt back.
You'll notice that we didn't say anything about printing
ing the string, even though that's in fact what happened.
This was very much on purpose: the code we typed in doesn't
know anything about printing strings. It knew how to get a
string object, and it knew how to send a message to that
object. That's the end of the story for the code we wrote.
But for fun, let's take a look at what happened when the
string object received the @code{printNl} message. The string object
then went to a table @footnote{Which table? This is determined by the type
of the object. An object has a type, known as the
class to which it belongs. Each class has a table
of methods. For the object we created, it is
known as a member of the @code{String} class. So we go
to the table associated with the String class.}
which lists the messages which strings can receive, and what code to
execute. It found that there is indeed an entry for
@code{printNl} in that table and ran this code. This code then walked through
its characters, printing each of them out to the terminal. @footnote{
Actually, the message @code{printNl} was inherited
from Object. It sent a @code{print} message, also
inherited by Object, which then sent @code{printOn:} to
the object, specifying that it print to the @code{Transcript}
object. The String class then prints its characters to the
standard output.}
The central point is that an object is entirely self-contained;
only the object knew how to print itself out. When we want an
object to print out, we ask the object itself to do the printing.
@node Doing math
@subsection Doing math
A similar piece of code prints numbers:
@example
1234 printNl
@end example
Notice how we used the same message, but have sent it to a
new type of object---an integer (from class @code{Integer}). The
way in which an integer is printed is much different from
the way a string is printed on the inside, but because we
are just sending a message, we do not have to be aware of
this. We tell it to @code{printNl}, and it prints itself out.
As a user of an object, we can thus usually send a particular
message and expect basically the same kind of behavior,
regardless of object's internal structure (for
instance, we have seen that sending @code{printNl} to an object
makes the object print itself). In later chapters we will
see a wide range of types of objects. Yet all of them can
be printed out the same way---with @code{printNl}.
White space is ignored, except as it separates words.
This example could also have looked like:
@example
1234 printNl
@end example
However, @gst{} tries to execute each line by itself if
possible. If you wanted to write the code on two lines, you
might have written something like:
@example
(1234
printNl)
@end example
From now on, we'll omit @code{printNl} since @gst{}
does the service of printing the answer for us.
An integer can be sent a number of messages in addition
to just printing itself. An important set of messages for
integers are the ones which do math:
@example
9 + 7
@end example
Answers (correctly!) the value 16. The way that it does
this, however, is a significant departure from a procedural
language.
@node Math in Smalltalk
@subsection Math in Smalltalk
In this case, what happened was that the object @code{9} (an
Integer), received a @code{+} message with an argument of @code{7}
(also an Integer). The @code{+} message for integers then caused
Smalltalk to create a new object @code{16} and return it as the
resultant object. This @code{16} object was then given the
@code{printNl} message, and printed @code{16} on the terminal.
Thus, math is not a special case in Smalltalk; it is
done, exactly like everything else, by creating objects, and
sending them messages. This may seem odd to the Smalltalk
novice, but this regularity turns out to be quite a boon:
once you've mastered just a few paradigms, all of the language
``falls into place''. Before you go on to the next
chapter, make sure you try math involving @code{*} (multiplication),
@code{-} (subtraction), and @code{/} (division) also. These
examples should get you started:
@example
8 * (4 / 2)
8 - (4 + 1)
5 + 4)
2/3 + 7
2 + 3 * 4
2 + (3 * 4)
@end example
@node Some classes
@section Using some of the Smalltalk classes
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.
@menu
* Arrays:: An array in Smalltalk
* Sets:: A set in Smalltalk
* Dictionaries:: Getting more sophisticated, eh?
* Closing thoughts:: There always ought to be some closing thoughts
@end menu
@node Arrays
@subsection An array in Smalltalk
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@footnote{
@gst{} supports completion in the same way as Bash or @sc{gdb}.
To enter the following line, you can for example type
@samp{x := Arr@kbd{<TAB>} new: 20}. This can come in handy
when you have to type long names such as @code{IdentityDictionary},
which becomes @samp{Ide@kbd{<TAB>}D@kbd{<TAB>}}. Everything
starting with a capital letter or ending with a colon can
be completed.}:
@example
x := Array new: 20
@end example
The @code{Array new: 20} creates the array; the @code{x :=} part
connects the name @code{x} with the object. Until you assign
something else to @code{x}, you can refer to this array by the name
@code{x}. Changing elements of the array is not done using the
@code{:=} 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:
@example
x at: 1
@end example
@noindent
which prints:
@example
nil
@end example
The slots of an array are initially set to ``nothing'' (which
Smalltalk calls @code{nil}). Let's set the first slot to the
number 99:
@example
x at: 1 put: 99
@end example
@noindent
and now make sure the 99 is actually there:
@example
x at: 1
@end example
@noindent
which then prints out:
@example
99
@end example
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 `:'.@footnote{Alert readers will remember that the math
examples of the previous chapter deviated from this.}
So when we said @code{x at: 1} we were sending a message to whatever
object was currently bound to @code{x} with an argument of 1. For an
array, this results in the first slot of the array being returned.
The second operation, @code{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 @code{at:} and
@code{at:put:} messages.
There is quite a bit of sanity checking built into an
array. The request
@example
6 at: 1
@end example
@noindent
fails with an error; 6 is an integer, and can't be indexed. Further,
@example
x at: 21
@end example
@noindent
fails with an error, because the array we created only has
room for 20 objects.
Finally, note that the object stored
in an array is just like any other object, so we can do
things like:
@example
(x at: 1) + 1
@end example
@noindent
which (assuming you've been typing in the examples) will
print 100.
@node Sets
@subsection A set in Smalltalk
We're done with the array we've been using, so we'll
assign something new to our @code{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 @i{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:
@example
x := Set new
@end example
@noindent
which creates an empty set. To view its contents, do:
@example
x
@end example
The kind of object is printed out (i.e., @code{Set}), and then the
members are listed within parenthesis. Since it's empty, we
see:
@example
Set ()
@end example
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 @code{.} period:
@example
x add: 5. x add: 7. x add: 'foo'
@end example
Like Pascal, and unlike C, statements are separated rather than
terminated. Thus you need only use a @code{.} when you have finished
one statement and are starting another. This is why our last statement,
@code{^r}, does not have a @code{.} following. Once again like Pascal,
however, Smalltalk won't complain if your enter a spurious
statement separator after @i{the last} statement.
However, we can save a little typing by using a Smalltalk shorthand:
@example
x add: 5; add: 7; add: 'foo'
@end example
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 @code{; add: 7} is the same as saying
@code{x add: 7}, because @code{x} was the last thing a message was sent
to.
his may not seem like such a big savings, but compare
the ease when your variable is named @code{aVeryLongVariableName}
instead of just @code{x}! We'll revisit some other occasions
where @code{;} 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'':
@example
x
@end example
@noindent
we'll see that it now contains our data:
@example
Set ('foo' 5 7)
@end example
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:
@example
x add:5; add: 5; add: 5; add: 5; yourself
@end example
We've added @i{5} several times, but when we printed our set
back out, we just see:
@example
Set ('foo' 5 7)
@end example
@code{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 @code{add: 5},
which happens to be @code{5} simply. There's nothing magic in
@code{yourself}; it is a unary message like @code{printNl},
which does nothing but returning the object itself. So you
can do this too:
@example
x yourself
@end example
What you put into a set with @code{add:}, you can take out
with @code{remove:}. Try:
@example
x remove: 5
x printNl
@end example
The set now prints as:
@example
Set ('foo' 7)
@end example
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:
@example
x includes: 7
x includes: 5
@end example
From which we see that x does indeed contain 7, but not 5.
Notice that the answer is printed as @code{true} or @code{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:
@node Dictionaries
@subsection Dictionaries
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:
@example
y := Dictionary new
y at: 'One' put: 1
y at: 'Two' put: 2
y at: 1 put: 'One'
y at: 2 put: 'Two'
@end example
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 @code{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:
@example
y at: 1
y at: 'Two'
@end example
which prints respectively:
@example
'One'
2
@end example
We can also ask a dictionary to print itself:
@example
y
@end example
@noindent
which prints:
@example
Dictionary (1->'One' 2->'Two' 'One'->1 'Two'->2 )
@end example
@noindent
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:
@example
y
x!
@end example
The exclamation mark deleted @gst{}'s knowledge of both
variables. Asking for them again will return just @code{nil}.
@node Closing thoughts
@subsection Closing thoughts
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.
@node The hierarchy
@section The Smalltalk class hierarchy
When programming in Smalltalk, you sometimes need to
create new kinds of objects, and define what various
messages will do to these objects. In the next chapter we will
create some new classes, but first we need to understand how
Smalltalk organizes the types and objects it contains.
Because this is a pure ``concept'' chapter, without any actual
Smalltalk code to run, we will keep it short and to the
point.
@menu
* Class Object:: The grandfather of every class
* Animals:: A classic in learning OOP!
* But why:: The bottom line of the class hierarchy
@end menu
@node Class Object
@subsection Class @code{Object}
Smalltalk organizes all of its classes as a tree hierarchy.
At the very top of this hierarchy is class @i{Object}.
Following somewhere below it are more specific classes, such
as the ones we've worked with---strings, integers, arrays, and
so forth. They are grouped together based on their similarities;
for instance, types of objects which may be compared
as greater or less than each other fall under a class known
as @i{Magnitude}.
One of the first tasks when creating a new object is to
figure out where within this hierarchy your object falls.
Coming up with an answer to this problem is at least as much
art as science, and there are no hard-and-fast rules to nail
it down. We'll take a look at three kinds of objects to
give you a feel for how this organization matters.
@node Animals
@subsection Animals
Imagine that we have three kinds of objects, representing
@i{Animals}, @i{Parrots}, and @i{Pigs}. Our messages will be
@i{eat}, @i{sing}, and @i{snort}. Our first pass at
inserting these objects into the Smalltalk hierarchy would
organize them like:
@example
@r{Object}
@r{Animals}
@r{Parrots}
@r{Pigs}
@end example
This means that Animals, Parrots, and Pigs are all direct
descendants of @i{Object}, and are not descendants of each
other.
Now we must define how each animal responds to each
kind of message.
@example
@r{Animals}
@r{eat --> Say ``I have now eaten''}
@r{sing --> Error}
@r{snort --> Error}
@r{Parrots}
@r{eat --> Say ``I have now eaten''}
@r{sing --> Say ``Tweet''}
@r{snort --> Error}
@r{Pigs}
@r{eat --> Say ``I have now eaten"''}
@r{sing --> Error}
@r{snort --> Say ``Oink''}
@end example
Notice how we kept having to indicate an action for @i{eat}.
An experienced object designer would immediately recognize
this as a clue that we haven't set up our hierarchy correctly.
Let's try a different organization:
@example
@r{Object}
@r{Animals}
@r{Parrots}
@r{Pigs}
@end example
That is, Parrots inherit from Animals, and Pigs from Parrots.
Now Parrots inherit all of the actions from Animals,
and Pigs from both Parrots and Animals. Because of this
inheritance, we may now define a new set of actions which
spares us the redundancy of the previous set:
@example
@r{Animals}
@r{eat --> Say ``I have now eaten''}
@r{sing --> Error}
@r{snort --> Error}
@r{Parrots}
@r{sing --> Say ``Tweet''}
@r{Pigs}
@r{snort --> Say ``Oink''}
@end example
Because Parrots and Pigs both inherit from Animals, we have
only had to define the @i{eat} action once. However, we have
made one mistake in our class setup---what happens when we
tell a Pig to @i{sing}? It says ``Tweet'', because we have put
Pigs as an inheritor of Parrots. Let's try one final
organization:
@example
@r{Object}
@r{Animals}
@r{Parrots}
@r{Pigs}
@end example
Now Parrots and Pigs inherit from Animals, but not from each
other. Let's also define one final pithy set of actions:
@example
@r{Animals}
@r{eat --> Say ``I have eaten''}
@r{Parrots}
@r{sing --> Say ``Tweet''}
@r{Pigs}
@r{snort --> Say ``Oink''}
@end example
The change is just to leave out messages which are inappropriate.
If Smalltalk detects that a message is not known by
an object or any of its ancestors, it will automatically
give an error---so you don't have to do this sort of thing
yourself. Notice that now sending @i{sing} to a Pig does
indeed not say ``Tweet''---it will cause a Smalltalk error
instead.
@node But why
@subsection The bottom line of the class hierarchy
The goal of the class hierarchy is to allow you to
organize objects into a relationship which allows a particular
object to inherit the code of its ancestors. Once you
have identified an effective organization of types, you
should find that a particular technique need only be implemented
once, then inherited by the children below. This
keeps your code smaller, and allows you to fix a bug in a
particular algorithm in only once place---then have all users
of it just inherit the fix.
You will find your decisions for adding objects change
as you gain experience. As you become more familiar with
the existing set of objects and messages, your selections
will increasingly ``fit in'' with the existing ones. But even
a Smalltalk @i{pro} stops and thinks carefully at this stage,
so don't be daunted if your first choices seem difficult and
error-prone.
@node Creating classes
@section Creating a new class of objects
With the basic techniques presented in the preceding
chapters, we're ready do our first real Smalltalk program.
In this chapter we will construct three new types of objects
(known as @i{classes}), using the Smalltalk technique of
inheritance to tie the classes together, create new objects
belonging to these classes (known as creating instances of
the class), and send messages to these objects.
We'll exercise all this by implementing a toy home-finance
accounting system. We will keep track of our overall
cash, and will have special handling for our checking
and savings accounts. From this point on, we will be defining
classes which will be used in future chapters. Since
you will probably not be running this whole tutorial in one
Smalltalk session, it would be nice to save off the state of
Smalltalk and resume it without having to retype all the
previous examples. To save the current state of @gst{},
type:
@example
ObjectMemory snapshot: 'myimage.im'
@end example
@noindent
and from your shell, to later restart Smalltalk from this
``snapshot'':
@example
@b{$} gst -I myimage.im
@end example
Such a snapshot currently takes a little more than a megabyte,
and contains all variables, classes, and definitions you
have added.
@menu
* A new class:: Creating a new class
* Documenting the class:: So anybody will know what it's about
* Defining methods:: So it will be useful
* Instance methods:: One of two kind of methods (the others,
class methods, are above)
* A look at our object:: which will sorely show that something
is still missing.
* Moving money around:: Let's make it more fun!
* Next coming:: Yeah, what's next?!?
@end menu
@node A new class
@subsection Creating a new class
Guess how you create a new class? This should be getting
monotonous by now---by sending a message to an object.
The way we create our first ``custom'' class is by sending the
following message:
@example
Object subclass: #Account.
Account instanceVariableNames: 'balance'.
@end example
Quite a mouthful, isn't it? @gst{} provides a
simpler way to write this, but for now let's stick with this.
Conceptually, it isn't really that bad. The Smalltalk variable
@i{Object} is bound to the grand-daddy of all classes on the
system. What we're doing here is telling the @i{Object} class
that we want to add to it a subclass known as @i{Account}.
Then, @code{instanceVariableNames: 'balance'} tells the new
class that each of its objects (@dfn{instances}) will have a
hidden variable named @code{balance}.
@node Documenting the class
@subsection Documenting the class
The next step is to associate a description with the
class. You do this by sending a message to the new class:
@example
Account comment:
'I represent a place to deposit and withdraw money'
@end example
A description is associated with every Smalltalk class, and
it's considered good form to add a description to each new
class you define. To get the description for a given class:
@example
Account comment
@end example
And your string is printed back to you. Try this with class
Integer, too:
@example
Integer comment
@end example
However, there is another way to define classes. This still
translates to sending objects, but looks more like a traditional
programming language or scripting language:
@example
Object subclass: Account [
| balance |
<comment:
'I represent a place to deposit and withdraw money'>
]
@end example
This has created a class. If we want to access it again, for
example to modify the comment, we can do so like this:
@example
Account extend [
<comment:
'I represent a place to withdraw money that has been deposited'>
]
@end example
This instructs Smalltalk to pick an existing class, rather than
trying to create a subclass.
@node Defining methods
@subsection Defining a method for the class
We have created a class, but it isn't ready to do any
work for us---we have to define some messages which the class
can process first. We'll start at the beginning by defining
methods for instance creation:
@example
Account class extend [
new [
| r |
<category: 'instance creation'>
r := super new.
r init.
^r
]
]
@end example
The important points about this are:
@itemize @bullet
@item
@code{Account class} means that we are defining messages which are
to be sent to the Account class itself.
@item
@code{<category: 'instance creation'>}
is more documentation support; it says that the methods
we are defining supports creating objects of type
Account.
@item
The text starting with @code{new [} and ending with @code{]}
defined what action to take for the message @code{new}.
When you enter this definition, @gst{} will simply
give you another prompt, but your method has been compiled in
and is ready for use. @gst{} is pretty quiet on successful
method definitions---but you'll get plenty of error
messages if there's a problem!
If you're familiar with other Smalltalks, note that the body
of the method is always in brackets.
@end itemize
The best way to describe how this method works is to
step through it. Imagine we sent a message to the new class
Account with the command line:
@example
Account new
@end example
@code{Account} receives the message @code{new} and looks up
how to process this message. It finds our new definition, and
starts running it. The first line, @code{| r |}, creates a local
variable named @code{r} which can be used as a placeholder for
the objects we create. @code{r} will go away as soon as the message
is done being processed; note the parallel with @code{balance}, which
goes away as soon as the object is not used anymore. And note that
here you have to declare local variables explicitly, unlike what
you did in previous examples.
The first real step is to actually create the object.
The line @code{r := super new} does this using a fancy trick.
The word @code{super} stands for the same object that the message
@code{new} was originally sent to (remember? it's @code{Account}),
except that when Smalltalk goes to search for the methods,
it starts one level higher up in the hierarchy than the current
level. So for a method in the Account class, this is
the Object class (because the class Account inherits from is
Object---go back and look at how we created the Account
class), and the Object class' methods then execute some code
in response to the @code{#new} message. As it turns out, Object
will do the actual creation of the object when sent a @code{#new}
message.
One more time in slow motion: the Account method @code{#new}
wants to do some fiddling about when new objects are created,
but he also wants to let his parent do some work with
a method of the same name. By saying @code{r := super new} he
is letting his parent create the object, and then he is attaching
it to the variable @code{r}. So after this line of code executes,
we have a brand new object of type Account, and @code{r}
is bound to it. You will understand this better as time
goes on, but for now scratch your head once, accept it as a
recipe, and keep going.
We have the new object, but we haven't set it up correctly.
Remember the hidden variable @code{balance} which we saw
in the beginning of this chapter? @code{super new} gives us the
object with the @code{balance} field containing nothing, but we want
our balance field to start at 0. @footnote{And unlike C, Smalltalk
draws a distinction between @code{0} and @code{nil}. @code{nil}
is the @i{nothing} object, and you will receive an error if you
try to do, say, math on it. It really does matter that we
initialize our instance variable to the number 0 if we wish
to do math on it in the future.}
So what we need to do is ask the object to set itself up.
By saying @code{r init}, we are sending the @code{init}
message to our new Account. We'll define
this method in the next section---for now just assume that
sending the @code{init} message will get our Account set up.
Finally, we say @code{^r}. In English, this is @i{return what
r is attached to}. This means that whoever sent to Account
the @code{new} message will get back this brand new account. At
the same time, our temporary variable @code{r} ceases to exist.
@node Instance methods
@subsection Defining an instance method
We need to define the @code{init} method for our Account
objects, so that our @code{new} method defined above will work.
Here's the Smalltalk code:
@example
Account extend [
init [
<category: 'initialization'>
balance := 0
]
]
@end example
It looks quite a bit like the previous method definition,
except that the first one said
@code{Account class extend}, and ours says
@code{Account extend}.
The difference is that the first one defined a method for
messages sent directly to @code{Account}, but the second one is
for messages which are sent to Account objects once they are
created.
The method named @code{init} has only one line, @code{balance := 0}.
This initializes the hidden variable @code{balance} (actually
called an instance variable) to zero, which makes
sense for an account balance. Notice that the method
doesn't end with @code{^r} or anything like it: this method
doesn't return a value to the message sender. When you do
not specify a return value, Smalltalk defaults the return
value to the object currently executing. For clarity of
programming, you might consider explicitly returning @code{self}
in cases where you intend the return value to be used.@footnote{
And why didn't the designers default the
return value to nil? Perhaps they didn't appreciate
the value of void functions. After all, at
the time Smalltalk was being designed, C didn't
even have a void data type.}
@node A look at our object
@subsection Looking at our Account
Let's create an instance of class Account:
@example
a := Account new
@end example
Can you guess what this does? The @code{Smalltalk at: #a put: <something>}
creates a Smalltalk variable. And the @code{Account new} creates a new
Account, and returns it. So this line creates a Smalltalk
variable named @code{a}, and attaches it to a new Account---all in
one line. It also prints the Account object we just created:
@example
an Account
@end example
Hmmm... not very informative. The problem is that we didn't
tell our Account how to print itself, so we're just getting
the default system @code{printNl} method---which tells what the
object is, but not what it contains. So clearly we must add
such a method:
@example
Account extend [
printOn: stream [
<category: 'printing'>
super printOn: stream.
stream nextPutAll: ' with balance: '.
balance printOn: stream
]
]
@end example
Now give it a try again:
@example
a
@end example
@noindent
which prints:
@example