"Smalltalk-80, the Language" by Adele Goldberg and David Robson Published by Addison-Wesley ISBN 0-201-13688-0
The IDE currently has a few limitations compared to traditional Smalltalk environments. First, there is no way to evaulate expressions in a workspace---this is because the virtual machine running on the PalmPilot makes use of many features of the Palm operating system which would be very difficult (and slow) to simulate within the IDE. In the future, the system may support either simulation of a limited subset of the virtual machine within the IDE, or else a serial link to the PalmPilot (or an emulator) permitting workspace-like functionality.
In addition, there is no way to create complex objects at compile time. Simple literals such as strings and arrays may be embedded in methods as usual, but initialization of class variables and related things must be performed at runtime. This is generally not a very severe limitation, and it is eased somewhat by the fact that the IDE allows you to define some extra kinds of objects at compile time which are not allowed by traditional Smalltalks (for example, IdentityDictionaries can be created at compile time).
Despite these limitations, Pocket Smalltalk is a very practical alternative to C or C++ for developing palmtop or PDA applications.
Object Behavior Class Metaclass BlockClosure FullBlockClosure Boolean True False Character Collection KeyedCollection ArrayedCollection Array ByteArray List* OrderedCollection String Dictionary* IdentityDictionary* Set* IdentitySet* ExceptionHandler Message MiniDebugger* Number Integer SmallInteger LongInteger Fraction* Point* Smalltalk Stream* ReadStream* WriteStream* UndefinedObject
It is illegal to return from the Smalltalk class>>#start method. Doing so will likely crash the virtual machine. Instead, you should execute "Smalltalk quit" to stop your program.
A symbol is written as #symbolName, where symbolName is any valid Smalltalk identifier.
Since symbol data accounts for a large fraction of the total size of a typical Smalltalk program, Pocket Smalltalk will replace each symbol by a unique SmallInteger. As a consequence, there is no Symbol class, nor is there a way to distinguish between symbols and integers. This is almost never a problem, though, and if necessary, symbols can be "wrapped" in another class to provide the desired functionality.
This optimization saves a considerable amount of memory space and execution time. The only real disadvantage, aside from losing the distinction between Symbols and SmallIntegers, is that you will be unable to access the characters of a symbol (for example, in order to print the symbol). Again, this should not be a problem since Symbols should not be printed at runtime anyways (Strings should be used for this purpose).
For debugging purposes, you may choose to include the text of each symbol (select the "emit debug info" option in the IDE). Then you may use the expression:
Context textOfSymbol: symbolto recover the String containing the symbol's characters. The default MiniDebugger uses this feature to provide a symbolic stack trace when an error occurs.
Smalltalk snapshotThe next time your program is started, it will resume exactly where it left off.
Smalltalk at: #ClassNameor:
Smalltalk includesKey: #ClassName
You cannot add or remove classes (or methods) at runtime.
The Smalltalk class also provides various other system operations which can be seen by browsing the class.
Nonlocal returns through arbitrary stack frames may be accomplished by the following methods:
ExceptionHandler class>>#catch:during: ExceptionHandler class>>#throw:
#catch:during: takes as its first argument a 1-argument block which is evaulated with a thrown object if a #throw: message is sent during the execution of the second argument of #catch:during: (a 0-argument block). Any object may be "thrown". For example:
ExceptionHandler catch: [:object | ('caught: ', object printString) print] during: [ExceptionHandler throw: 12345].If no #catch:during: method is extant when a #throw: message is sent, the method ExceptionHandler class>>#uncaughtThrow: is sent (with the thrown object as an argument).
There is no provision for "unwind protection" or proceedable exceptions.
By default, #doesNotUnderstand: just signals an error, but certain classes may want to intercept #doesNotUnderstand: and take some special action.
A class which provides very little behavior of its own, but instead forwards most messages onto another object is called a "proxy". Proxies and other classes with similar needs can subclass from nil instead of from Object (or a subclass of Object), thereby inheriting none of the "basic" methods defined by class Object. They may then use #doesNotUnderstand: to forward messages to another object.
A class inheriting from nil need only implement the one selector: #doesNotUnderstand:. The cross compiler does not allow you to create a subclass of nil which does not implement this selector.
The built-in collection classes implement expansion by means of #become:. This allows a collection to be represented by a single object, rather than two objects as in some Smalltalk implementations.
Collection includesSelector: #do: Set canUnderstand: #keys 15 respondsTo: #+ Array methodCount Object selectorsNote that #perform: and related methods can be used as usual.
At compile time, references to class (and "global") variables are converted into single instructions. No separate objects are created for global variables; nor can you set the value of a global variable at compile time (it must be done with some kind of initialization code at runtime).
Unlike other Smalltalks, classes are not global variables. For most purposes, you can treat them as such, but the major difference is that you cannot assign to them. Class names must not conflict with class variable names.
object isNil ifTrue: [...]This expression can be simplified by defining a new message #ifNil: so that you can write:
object ifNil: [...]The problem with doing this is that ordinary Smalltalks cannot apply compiler optimizations to this expression, so the above code will execute more slowly and take more space than the usual isNil ifTrue: case. Pocket Smalltalk, however, knows how to optimize ifNil: and related messages, so you can use them without any penalty. The message forms it recognizes are as follows:
^name orIfNil: ['anonymous']
Pocket Smalltalk bypasses the dynamic memory scheme imposed by PalmOS and allocates chunks of memory as database records. It then disables write protection on these records in order to write into them. In this manner, the entire memory of the PalmPilot can be used to store objects, and no extra memory is needed to make image snapshots, since the objects are already stored in an appropriate format within the database records. Records are allocated and de-allocated as the memory needs of the Smalltalk program change.
In order to effectively support the automatic memory management (garbage collection) required by Smalltalk, an indirect object table is used. This object table is configured (at compile time) to support a fixed maximum number of live objects simultaneously. Each object table index identifies an object and can be one of 2^15-1 (32767) different values. Therefore, up to 32767 different objects can be active at one time (not counting methods, symbols, small integers, or method dictionaries). (The 32768th object is used as a special tag for certain system operations.)
Each object table entry contains a 4-byte pointer to the beginning of the corresponding object. The objects reside in database records as described above. Because of limitations in PalmOS versions previous to 3.0, the maximum size of the object table is 64k---and probably less, due to heap fragmentation. Therefore, you should not rely on more than 32k to be available for the object table, giving 32k / 4 = 8192 object table entries. Although 8192 objects may not seem like much, there are really very few programs that will need this many objects. You are more likely to run out of memory to store the objects in than you are to run out of object table slots to refer to them. Typical programs of around 200 classes can run quite happily in under 1000 object table slots and perhaps 20k of heap memory. However, if you need more object table slots, it is generally safe to increase the maximum to around 16000 slots. This may force users of PalmOS v2.0 (and previous versions) to "defragment" their machines before using your program, however.
Garbage collection is implemented by a two-pass mark-compact collector. First, the reachable objects are discovered by tracing pointers starting at the roots (basically the objects on the data stack). Then, each database record containing objects is scanned. Unreachable objects are discarded (and their object table entries recycled), while reachable objects are "slid" down toward the beginning of each database record. After each record is scanned, all the reachable objects will be consolidated at the beginning of the record, while the rest of the record will consist of free space. As a consequence, allocation of new objects is very quick, as heap fragmentation cannot occur.
The objects statically allocated at compile time (classes, metaclasses, and literals) are never scanned or reclaimed. Therefore, having more literals or classes in your program will not slow down garbage collection.
Garbage collection of a typical 20k heap takes less than 0.1 seconds on the PalmPilot, so you will probably never even notice a pause due to memory management.
A slightly extended syntax is provided for Character literals. In addition to the usual $x syntax, you can use the following "escape" sequences to get special characters:
$\newline, $\space, $\tab, $\backspace, $\cr, $\lf, $\escape, $\backslash
You can also specify a character directly by ASCII code by giving it in the form: $\xxx where xxx is the ASCII code.
Names of classes are discarded at runtime to avoid taking space, but if you instruct the compiler to emit debugging information the class names will be available by sending the class the message #name. Metaclasses respond to #name by answering the name of their unique instance followed by 'class', e.g.:
Collection class name => 'Collection class'
Most of the functionality of blocks is available. In particular, blocks may access (and assign to) variables in enclosing scopes. Nonlocal returns are also supported, as are "recursive" (reentrant) blocks. The main restriction on blocks is that they may not refer to variables in enclosing scopes which have already returned. This is almost never a problem in practice provided that you do not hold onto blocks in instance variables or global variables. For such purposes you should use a Message or a MessageSend object instead of a block.
Attempts to access an variable (from a block) in an enclosing scope which has already returned will result in the message #outerScopeInvalid being sent to the block, which by default signals an error. Similarly, attempting to perform a nonlocal return from a block whose home context has alreay returned will send #alreadyReturned to the block.
Blocks are currently classified into 4 categories depending on what kinds of actions they perform:
If you have any comments or questions about this system please e-mail me at the address below.