Back: Invoking code blocks
Up: Tutorial
Forward: Simple errors
 
Top: GNU Smalltalk User's Guide
Contents: Table of Contents
Index: Class index
About: About this document

5.8 When Things Go Bad

So far we've been working with examples which work the first time. If you didn't type them in correctly, you probably received a flood of unintelligible complaints. You probably ignored the complaints, and typed the example again.

When developing your own Smalltalk code, however, these messages are the way you find out what went wrong. Because your objects, their methods, the error printout, and your interactive environment are all contained within the same Smalltalk session, you can use these error messages to debug your code using very powerful techniques.

5.8.1 A Simple Error  Those that only happen in examples
5.8.2 Nested Calls  Those that actually happen in real life
5.8.3 Looking at Objects  Trying to figure it out


5.8.1 A Simple Error

First, let's take a look at a typical error. Type:
 
   7 plus: 1 !

This will print out:
 
   7 did not understand selector 'plus:'
   <blah blah>
   UndefinedObject>>#executeStatements

The first line is pretty simple; we sent a message to the 7 object which was not understood; not surprising since the plus: operation should have been +. Then there are a few lines of gobbledegook: just ignore them, they reflect the fact that the error passed throgh GNU Smalltalk's exception handling system. The remaining line reflect the way the GNU Smalltalk invokes code which we type to our command prompt; it generates a block of code which is invoked via an internal method executeStatements defined in class Object and evaluated like nil executeStatements (nil is an instance of UndefinedObject). Thus, this output tells you that you directly typed a line which sent an invalid message to the 7 object.

All the error output but the first line is actually a stack backtrace. The most recent call is the one nearer the top of the screen. In the next example, we will cause an error which happens deeper within an object.


5.8.2 Nested Calls

Type the following lines:
 
   Smalltalk at: #x put: (Dictionary new) !
   x at: 1 !

The error you receive will look like:
 
   Dictionary new: 31 "<0x33788>" error: key not found
   ...blah blah...
   Dictionary>>#error:
   [] in Dictionary>>#at:
   [] in Dictionary>>#at:ifAbsent:
   Dictionary(HashedCollection)>>#findIndex:ifAbsent:
   Dictionary>>#at:ifAbsent:
   Dictionary>>#at:
   UndefinedObject(Object)>>#executeStatements

The error itself is pretty clear; we asked for something within the Dictionary which wasn't there. The object which had the error is identified as Dictionary new: 31. A Dictionary's default size is 31; thus, this is the object we created with Dictionary new.

The stack backtrace shows us the inner structure of how a Dictionary responds to the #at: message. Our hand-entered command causes the usual entry for UndefinedObject(Object). Then we see a Dictionary object responding to an #at: message (the "Dictionary>>#at:" line). This code called the object with an #at:ifAbsent: message. All of a sudden, Dictionary calls that strange method #findIndex:ifAbsent:, which evaluates two blocks, and then the error happens.

To understand this better, it is necessary to know that a very common way to handle errors in Smalltalk is to hand down a block of code which will be called when an error occurs. For the Dictionary code, the at: message passes in a block of code to the at:ifAbsent: code to be called when at:ifAbsent: can't find the given key, and at:ifAbsent: does the same with findIndex:ifAbsent:. Thus, without even looking at the code for Dictionary itself, we can guess something of the code for Dictionary's implementation:

 
   findIndex: key ifAbsent: errCodeBlock
       ...look for key...
       (keyNotFound) ifTrue: [ ^(errCodeBlock value) ]
       ...

   at: key
       ^self at: key ifAbsent: [^self error: 'key not found']

Actually, findIndex:ifAbsent: lies in class HashedCollection, as that Dictionary(HashedCollection) in the backtrace says.

It would be nice if each entry on the stack backtrace included source line numbers. Unfortunately, at this point GNU Smalltalk doesn't provide this feature. Of course, you have the source code available...


5.8.3 Looking at Objects

When you are chasing an error, it is often helpful to examine the instance variables of your objects. While strategic calls to printNl will no doubt help, you can look at an object without having to write all the code yourself. The inspect message works on any object, and dumps out the values of each instance variable within the object.(29)

Thus:
 
   Smalltalk at: #x put: (Interval from: 1 to: 5) !
   x inspect !

displays:
 
   An instance of Interval
   start: 1
   stop: 5
   step: 1
   contents: [
       [1]: 1
       [2]: 2
       [3]: 3
       [4]: 4
       [5]: 5
   ]

We'll finish this chapter by emphasizing a technique which has already been covered: the use of the error: message in your own objects. As you saw in the case of Dictionary, an object can send itself an error: message with a descriptive string to abort execution and dump a stack backtrace. You should plan on using this technique in your own objects. It can be used both for explicit user-caused errors, as well as in internal sanity checks.




This document was generated on May, 12 2002 using texi2html