Next Previous Up Top Contents Index

2 Fixing Bugs

2.3 Problems at run time

Now we have taken a brief look at how Functional Developer treats compile-time problems, we will look at how it lets us debug problems that only emerge as exceptions at run time.

Note: The numbered example steps in this section lead us through a possible debugging scenario. In places the example is a little unrealistic. This is because usually you are familiar with at least some of the code you are debugging, and also because the main purpose of the example is to introduce features of Functional Developer.

1. With the rebuilt version of Reversi that compiled with no warnings, start a new game, with Application > Start.
2. After a couple of moves, save the new game by choosing File > Save in the Reversi window.
The Save dialog appears.
3. Choose a file to save into, and click Save.
An application error dialog appears.

Figure 2.3 A Dylan run-time application error.

The dialog appeared because the Functional Developer debugger caught an unhandled Dylan exception in the Reversi application. Something is wrong with the game-saving code. We must start up a debugger window to see what went wrong.

4. Choose Debug reversi.exe and click OK to enter the debugger.
The Functional Developer debugger appears. We discuss the debugger in detail in Chapter 6, "Debugging and Interactive Development".

In its uppermost pane, the debugger shows the error that it caught. It will be:

Dylan error: n is not of type {<class>: <BYTE-CHARACTER>}

where n is either 0, 1, or 2. (The value depends on the state of the game when we saved it. The reason for this will become clear shortly.)

In the left-hand pane beneath the message, there is a tree item for the master thread of the Reversi application. This tells us that the exception was raised in that thread. (In Reversi's case, there happens to be only one thread, but other applications might have multiple threads, and knowing the thread that raised the exception is useful. See Chapter 6 for more information about debugger options.)

When expanded, the tree item shows the current state of the call stack for Reversi's master thread. When the debugger is invoked on a thread, it pauses execution in that thread. So when we expand the tree we see the stack almost exactly as it was at the moment that the debugger was invoked.

The reason why what we see is almost exactly what the stack was like at the moment the debugger was invoked is that the stack pane normally filters out a lot of call frames that the Functional Developer run-time system creates. Because these are not frames that the running application creates directly, most of the time they are of no interest, and so it is convenient to hide them. You can change the filtering with the drop-down list available directly above the thread pane in the debugger. The default filter setting is "Filtered visible frames".

Figure 2.4 The Reversi application stack after a game-saving error.

Each item in the list is a call frame on the stack for the thread being debugged. We call this list of call frames a stack backtrace or simply a backtrace.

The backtrace shows frames in the order they were created, with the most recent at the top of the list. The frames are represented by the names of the functions whose call created them, and are accompanied by an icon denoting the sort of call it was. See Section 6.2.2.2 on page 100 for details of the icons and their meanings, but note for now that the green arrow icon represents the current location of the stack pointer--that is, the call at which the thread was paused.

2.3.1 - Searching the stack backtrace for the cause of the error
2.3.2 - Browsing local variables
2.3.3 - Browsing definitions
2.3.4 - Fixing the error
2.3.5 - Loading the saved game back in

Getting Started with Functional Developer - 31 MAR 2000

Next Previous Up Top Contents Index