home *** CD-ROM | disk | FTP | other *** search
- .SH
- Exploring and Creating
- .PP
- This document describes how to discover information about existing objects
- and create new objects using the Unix interface to the Little Smalltalk
- system (version two). The Little Smalltalk system running
- under different operating
- systems may have a slightly different interface, and the reader should be
- forewarned.
- .PP
- When you start version two Little Smalltalk under Unix, you will be given a
- prompt.
- You can enter expressions in response to the prompt, and the system will
- evaluate them (although it will not print the result unless you request
- it\s-2\u*\d\s+2).
- .FS
- * Note that this is a change from version one of Little Smalltalk, where
- expressions were automatically printed.
- The reason has to do with now expressions are compiled and executed
- now, using more Smalltalk code, and less C code.
- .FE
- .DS I
- > (5 + 7) print
- 12
- >
- .DE
- In Smalltalk one communicates with objects by passing messages to them.
- Even the addition sign shown above is treated as a message passed to the
- object 5, with argument 7. Other messages can be used to discover
- information about various objects.
- The most basic fact you can discover about an object is its class.
- This is given by the message \fBclass\fP, as in the following examples:
- .DS I
- > 7 class print
- Integer
- > nil class print
- UndefinedObject
- .DE
- .PP
- Occasionally, especially when programming, one would like to ask whether
- the class of an object matches some known class. One way to do this would
- be to use the message \fB=\!=\fP, which tells whether two expressions
- represent the same object:
- .DS I
- > ( 7 class =\!= Integer) print
- True
- > nil class == Object ; print
- False
- .DE
- .LP
- (Notice that second example uses cascades in place of parenthesis.
- The only difference between these two is that in the first example the
- result of the expression is the value returned by the print, whereas in the
- second the result of the expression is the value returned by =\!=. But
- since in any case the value is thrown away, it makes no difference.)
- .PP
- An easier way is to use the message \fBisMemberOf:\fP;
- .DS I
- > 7 isMemberOf: Integer ; print
- True
- > nil isMemberOf: Integer ; print
- False
- .DE
- .PP
- Sometimes you want to know if an object is an instance of a particular
- class or one if its subclasses; in this case the appropriate message is
- \fBisKindOf:\fP.
- .DS I
- > 7 isMemberOf: Number ; print
- False
- > 7 isKindOf: Number ; print
- True
- .DE
- .PP
- All objects will respond to the message \fBdisplay\fP by telling a little
- about themselves. Many just give their class and their printable
- representation:
- .DS I
- > 7 display
- (Class Integer) 7
- > nil display
- (Class UndefinedObject) nil
- .DE
- .LP
- Others, such as classes, are a little more verbose:
- .DS I
- > Integer display
- Class Name: Integer
- SuperClass: Number
- Instance Variables:
- no instance variables
- Subclasses:
- .DE
- .LP
- The display shows that the class \fBInteger\fP is a subclass of class
- \fBNumber\fP (that is, class \fBNumber\fP is the superclass of
- \fBInteger\fP). There are no instance variables for this class, and it
- currently has no subclasses.
- All of this information could be obtained by means of other messages,
- although the \fBdisplay\fP form is the easiest.
- .DS I
- > List variables display
- links
- > Integer superClass print
- Number
- > Collection subClasses display
- IndexedCollection
- Interval
- List
- .DE
- About the only bit of information that is not provided when one passes the
- message \fBdisplay\fP to a class
- is a list of methods the class responds to. There are two
- reasons for this omission; the first is that this list can often be quite
- long, and we don't want to scroll the other information off the screen
- before the user has seen it. The second reason is that there are really
- two different questions the user could be asking. The first is what
- methods are actually implemented in a given class. A dictionary containing
- the set of methods implemented in a class can be found by passing the
- message \fBmethods\fP to a class. Since we are only interested in the set
- of keys for this dictionary (that is, the message selectors), we can use
- the message \fBkeys\fP. Finally, as we saw with the message
- \fBsubClasses\fP shown above, our old friend \fBdisplay\fP prints this
- information out one method to a line:
- .DS I
- > True methods keys display
- #ifTrue:ifFalse:
- #not
- .DE
- .PP
- A second question that one could ask is what message selectors an instance of a
- given class will respond to, whether they are inherited from superclasses
- or are defined in the given class. This set is given in response to the
- message \fBrespondsTo\fP.
- .DS I
- > True respondsTo display
- #class
- #==
- #hash
- #isNil
- #display
- #=
- #basicSize
- #isMemberOf:
- #notNil
- #print
- #basicAt:put:
- #isKindOf:
- #basicAt:
- #printString
- #or:
- #and:
- #ifFalse:ifTrue:
- #ifTrue:
- #ifFalse:
- #not
- #ifTrue:ifFalse:
- .DE
- .PP
- Alternatively, one can ask whether instances of a given class will respond
- to a specific message by writing the message selector as a symbol:
- .DS I
- > ( String respondsTo: #print ) print
- True
- > String respondsTo: #+ ; print
- False
- .DE
- .PP
- The inverse of this would be to ask what classes contain methods for a
- given message selector. Class \fBSymbol\fP defines a method to yield just
- this information:
- .DS I
- > #+ respondsTo display
- Integer
- Number
- Float
- .DE
- .PP
- The method that will be executed in response to a given message selector
- can be displayed by means of the message \fBviewMethod:\fP
- .DS I
- > Integer viewMethod: #gcd:
- gcd: value
- (value = 0) ifTrue: [ \(ua self ].
- (self negative) ifTrue: [ \(ua self negated gcd: value ].
- (value negative) ifTrue: [ \(ua self gcd: value negated ].
- (value > self) ifTrue: [ \(ua value gcd: self ].
- \(ua value gcd: (self rem: value)
- .DE
- .PP
- New functionality can be added using the message \fBaddMethod\fP.
- When passed to an instance of \fBClass\fP, this message drops the user into
- a standard Unix Editor. A body for a new method can then be entered.
- When the user exists the editor, the method body is compiled. If it is
- syntactically correct, it is added to the methods for the class. If it is
- incorrect, the user is given the option of re-editing the method.
- .DS I
- > Integer addMethod
- \& ... drop into editor and enter the following text
- % x
- \(ua ( x + )
- \& ... exit editor
- compiler error: invalid expression start )
- edit again (yn) ?
- \& ...
- .DE
- .PP
- In a similar manner, existing methods can be editing by passing their
- selectors, as symbols to the message \fBeditMethod:\fP.
- .DS I
- > Integer editMethod: #gcd:
- \& ... drop into editor working on the body of gcd:
- .DE
- .PP
- The name of the editor used by these methods is taken from a string
- pointed to by the global variable \fIeditor\fP. Different editors can be
- selected merely by redefining this value:
- .DS I
- globalNames at: #editor put: 'emacs'
- .DE
- .PP
- Some Smalltalk systems make it very difficult for you to discover the
- bytecodes that a method gets translated into. Since the primary goal of
- Little Smalltalk is to help the student to discover how a modern very high
- leval language is implemented, it makes sense that the system should help
- you as much as possible discover everything about its internal structure.
- Thus a method, when presented with the message \fBdisplay\fP, will print
- out its bytecode representation.
- .DS I
- > Char methods at: #isAlphabetic ; display
- Method #isAlphabetic
- isAlphabetic
- ^ (self isLowercase) or: [ self isUppercase ]
-
- literals
- Array ( #isLowercase #isUppercase )
- bytecodes
- 32 2 0
- 144 9 0
- 0 0 0
- 250 15 10
- 8 0 8
- 32 2 0
- 144 9 0
- 1 0 1
- 242 15 2
- 241 15 1
- .DE
- .PP
- Bytecodes are represented by four bit opcodes and four bit operands, with
- occasional bytes representing data (more detail can be found in the book).
- The three numbers written on each line for the bytecodes represent the
- byte value followed by the upper four bits and the lower four bits.
- .PP
- New objects are created using the message \fBnew\fP.
- Within a method
- these can be assigned to instance varibles using the assignment arrow.
- .DS I
- \fBaMethod\fP
- x \(<- Set new.
- \&...
- .DE
- .PP
- The assignment arrow is not recognized at the topmost level. Instead,
- global variables (variables recognized in any context), are created by
- passing messages to \fBglobalNames\fP (below).
- .PP
- New classes, on the
- other hand, are created by sending a message \fBaddSubClass\fP to the class
- that will be the superclass of the new class. The user will then be
- interrogated for information to be associated with the new class:
- .DS I
- > Object addSubClass
- Class Name? Foo
- Instance Variables? x y z
- Add a method (yn) ? y
- \&...
- > Foo display
- Class Name: Foo
- Superclass: Object
- Instance Variables:
- x
- y
- z
- Subclasses:
- .DE
- .PP
- Classes created using \fBaddSubClass\fP will be automatically added to the
- list of global variables. Other global variables can be created merely by
- placing their name and value into the
- dictionary \fBglobalNames\fP\s-2\u*\d\s+2.
- .DS I
- > globalNames at: #version put: 2.1
-
- > version print
- 2.1
- .DE
- .FS
- * This is a change from version 1 of Little Smalltalk, where it was
- possible to create global variables merely by assiging a value to them at
- the command level. The change is an unfortunate consequence of the
- fact that more is done now
- is Smalltalk, and less in C. The bytecode interpreter now knows little
- about the object globalNames, in particular, the bytecode interpreter
- doesn't know how to add a new object; this is done entirely in Smalltalk
- code. One possiblity would be to automatically have the parser change an
- assignment at the command level into an at:put:, but this would seem to
- complicate the parser unnecessarily.
- .FE
- .PP
- If you have written a new class and want to print the class methods on a
- file you can use the message \fBfileOut:\fP, after first creating a file to
- write to. Both classes and individual methods can be filed out, and
- several classes and/or methods can be placed in one file.
- .DS I
- > globalNames at: #f put: File new
- > f name: 'foo.st'
- > f open: 'w'
- > Foo fileOut: f
- > Bar fileOut: f
- > Object fileOutMethod: #isFoo to: f
- > f close
- .DE
- .LP
- The file ``newfile'' will now have a printable representation of the
- methods for the class Foo.
- These can subsequently be filed back into a different smalltalk image.
- .DS I
- > globalNames at: #f put: File new
- > f name: 'foo.st'
- > f open: 'r'
- > f fileIn
- > 2 isFoo print
- False
- .DE
- .PP
- Finally, once the user has added classes and variables and made whatever other
- changes they want, the message \fBsaveImage\fP, passed to the pseudo
- variable \fBsmalltalk\fP, can be used to save an entire object image on a file.
- If the writing of the image is successful, a message will be displayed.
- .DS I
- > smalltalk saveImage
- Image name? newimage
- image newimage created
- >
- .DE
- .PP
- Typing control-D causes the interpreter to exit.
- .PP
- When the smalltalk system is restarted, an alternative image, such as the
- image just created, can be specified by giving its name on the argument
- line:
- .DS I
- st newimage
- .DE
- .PP
- Further information on Little Smalltalk can be found in the book.
- .SH
- Incompatabilities with the Book
- .PP
- It is unfortunately the case that during the transition from version 1 (the
- version described in the book) and version 2 (the new version that is one
- third the size and three times faster), certain changes to the user
- interface were required. I will describe these here.
- .PP
- The first incompatability comes at the very beginning. In version 1 there
- were a great number of command line options. These have all been
- eliminated in version two. In version two the only command line option is
- the file name of an image file.
- .PP
- In version 1 it is possible to create global variables simply by assigning
- to them. That is, a statement such as
- .DS I
- xx \(<- 27
- .DE
- when issued at the command level would create a new global variable.
- Since it is not possible to assign to an unknown name within a method, this
- in effect required the version one system to keep around two parsers, one
- for methods and another for command lines. These were replaced with a
- single parser in version two, which necessitated a change. Now to create a
- global variable one must first establish it in the dictionary, using the
- command
- .DS I
- globalNames at: #xx put: 27
- .DE
- It is not possible to use assignment to create a global variable in version
- two.
- .PP
- The interface to the editor has been changed. In version one this was
- handled by the system, and not by Smalltalk code. This required a command
- format that was clearly not a Smalltalk command, so that they could be
- distinguished. The convention adoped was to use an APL style system
- command:
- .DS I
- )e filename
- .DE
- In version two we have moved these functions into Smalltalk code. Now
- the problem is just the reverse, we need a command that is a Smalltalk
- command. In addition, in version one entire classes were edited at once,
- whereas in version two only individual methods are edited. As we have
- already noted, the new commands to add or edit methods are as follows:
- .DS I
- \fIclassname\fP addMethod
- \fIclassname\fP editMethod: \fImethodname\fP
- .DE
- .PP
- The only other significant syntactic change is the way primitive methods
- are invoked. In version one these were either named or numbered,
- something like the following:
- .DS I
- <primitive 37 a b>
- <IntegerAdd a b>
- .DE
- In version two we have simply eliminated the keyword \fBprimitive\fP, so
- primitives now look like:
- .DS I
- <37 a b>
- .DE
- .PP
- There are far fewer primitives in version two, and much more of the system
- is now performed using Smalltalk code.
- .PP
- In addition to these syntactic changes, there are various small changes in
- the class structure. I hope to have a document describing these changes at
- some point, but as of right now the code itself is the best description.
-