Press `Debug’ for hours of fun.
The Thanksgiving holiday weekend has just come to a close. In addition to the usual overeating with family, I spent a number of hours inside a Squeak Smalltalk image, trying to get some older programs to work again. These include Celeste (a mail reader), Scamper (a web browser), and a really nice glass teletype window emulator by Ian Piumarta that lets you have a TTY where you can telnet to a local Emacs. (Aside: As much as I’m about to rave about how wonderful Squeak is, Emacs is still the king of the hill when it comes to serious text editing.)
More precisely, I spent hours in the Squeak debugger. That’s what happens when you try to run an older Squeak program. Actually, it isn’t accurate at all to say that you “run a Squeak program”. There aren’t really separate “programs”. What you do is run a Squeak image and then load code (using changesets, or bits of code in a file) into that running image. If the code you load into that image tries to communicate with objects that don’t exist in that image, or if the new code is sending the wrong messages to the objects the image does know about, your “program” doesn’t work.
Although I’ve played around with Squeak a bit before, I’d never had occasion to use the debugger, or Squeak’s other development tools, in anger. The experience was pretty unlike other programming I’ve done. The high points:
- You can inspect anything at any time
- You can always send a message and see what happens
- Debugging feels like a conversation with a partner who will actually talk to you
Let’s take these one at a time. Remember: everything I’m saying here applies to your experience while in the debugger. In other words, we’re talking about the capabilities available to you when something is wrong – when you need it most!
You can inspect anything at any time
While you’re in the debugger, you can jump up and down the call stack. So what? every debugger can do that. Here’s something different, though: when you drive the debugger up and down the call stack, at each level, the text of the currently executing message is shown and highlighted. You can then jump into the text shown in the debugger just like any other program text in the environment, and inspect stuff. You can highlight the text of a block or a variable and “print it” to see its value, or inspect it in a new window. When you inspect an object in the debugger, it will show you its value at that point in the call stack. As I said, it opens up a new window, and in that new window you can see all of the values of that object: its instance variables, its caller, and so forth. What’s more, this isn’t a static view. You can use the interaction pane of the inspector window to send messages to the object! Here’s a screenshot of an actual Scamper-related object in the inspector, opened from the debugger (the message returning
nil is the one causing the problem, btw):
The inspector is also a workspace.
You can always send a message and see what happens
You can almost always send messages to objects, with rare exceptions. (I think I encountered one or two situations where an object was not “alive” anymore.) This includes while they are being debugged. In other words, five layers down the call stack, you can inspect an object, see what message was just sent to it, see what its current instance variables are set to, &c., and then send it a new, different message (hopefully one that will get it to do what you want!).
Debugging feels more like a conversation with a partner who will actually talk to you
Most of the time I’ve been in the Squeak debugger, I’ve had two other tools open right next to me: the Method Finder and the System Browser. The Method Finder is really neat. You type in something that you think (or hope) is a message name, hit enter, and Squeak shows you a list of messages that are something like what you typed. For each message it shows you, you can see its implementors (who provide the functionality) and its senders (who is sending this message). For each implementor or sender, you can click on the class name and a System Browser pops up with exactly that method under focus so you can play with it.
For example, as I’ve been trying to get Scamper up and running, there’ve been lots of messages being sent by Scamper to objects that don’t exist anymore in the latest Squeaks. By entering these into the Method Finder, I could verify that they had no implementors, and that the Scamper objects were the only ones sending these messages. This allowed me to isolate the source of problems pretty quickly. Then, using the System Browser, I could quickly see what messages different objects in the system would accept, and how what Scamper was trying to send them differed.
The pattern you fall into is very conversational. You begin to feel less like you are picking at bits with a pair of digital tweezers and a microscope, and more like you are doing something human: having a conversation. And unlike, say, running
gdb on a C or assembly program running on a Linux box, the system “talks” back to you and describes itself (at least in a more interesting way than its register contents). This makes debugging really much more fun.
As evidence, here’s a screenshot of Scamper running in a recent Squeak image – as you can see I’ve just hit a(nother) bump in the road by trying to read Reddit. The debugger is the pink window on the right, and it’s complaining that we’ve tried to send a message to an undefined object. Luckily the debugger was nice enough to select the text of the currently executing message so that I could inspect it and see that it’s just the undefined object. The
formatter shown is a
DHTMLFormatter object (and thus defined), but it’s returning
nil when we send the
currentFormData message. This kind of interactivity is pretty addictive!
That darn DHtmlFormatter again.
Oh, and since I mentioned it, here’s a screenshot of Piumarta’s TeletypeWindow running Emacs:
Dear Emacs, I can’t live… if living is without you…
Next up is to learn how to contribute some of these fixes back to Squeak-world.