One of great ways you can explore the guts of a program is to simply run it, poke around and observe results, both from the outside (you are clicking around GUI and observing the external state), and from the inside (adding logging, opening debugger and inspecting the inner state). Doing this is often both educational and fun.

In Pharo thanks to its empowering environment we are actively encouraged to do just that — explore, poke around and have fun. But when you are playing with powerful tools such as the debugger, you need to be aware of potential problems if you are using it as indiscriminately as I do.

I wanted to explore how code completion is done; I knew from my previous unrelated explorations that the main entry point is class called NECController ( Smalltalk tools codeCompletion ) There, a method handleKeystrokeBefore: aKeyboardEvent editor: anEditor caught my interest, so I did what I usually do — pause an execution so I can look around.

To do that you drop self halt wherever you want for the program to stop, and when the execution reaches that point it opens a debugger for you.

Cool! Now I can explore the method, inspect arguments, call some methods (hoping side-effects won’t wreck it). But when I started typing in the debugger something else happened instead:

I added the halt to a piece code of code that is executed every time I press a key… oops. And now I cannot even delete it, because that’s also typing. Thankfully, here I can still use mouse, select the incriminating line, cut it out and recompile.

But imagine that you are working with code that works with basics of Pharo’s GUI, such as cursor position. Here the picture is not so nice. Pro tip: if your image is still responsive, you can close all debuggers with World > Windows > Close all debuggers

It’s also possible that you will receive emergency debugger instead. But we want to avoid such situation altogether, but still explore the state. So how do we do that?

haltOnce

First option is to add self haltOnce instead.

Nothing will happen until we enable it; either through World > System > Enable halt/inspect once, or by executing Halt enableHaltOnce . Then it will execute the halt once and disable it again. Looking much better.

But maybe you want to make the halt conditional.

For that we have self haltIf:

As an argument we can provide a #symbol , or rather a method name. When the execution reaches the halt it will check the call chain and if any of the methods matches the symbol it will halt.

Now I can execute my whole test class and halt only in one specific instance. (Note: This is running in Moose platform which uses a different debugger.)

Finally I can give #haltIf: a block, which will trigger if it evaluates to true. Maybe you want to stop a method if an argument has suspicious values to investigate the perpetrator.

1 2 3 4 5 6 7 Point>>grid: aPoint "Answer a Point to the nearest rounded grid modules specified by aPoint." | newX newY | self haltIf: [ aPoint x < 0 | (aPoint y < 0) ]. newX := x + (aPoint x // 2) truncateTo: aPoint x. newY := y + (aPoint y // 2) truncateTo: aPoint y. ^ newX @ newY

Now 6.7@8.2 grid: 5@5 returns (5@10) , but 6.7@8.2 grid: -1@-1 opens a debugger instead of returning 5@7 (in this case -1@-1 is valid, but suspicious argument, so I want to find out who is sending it.).