Skip to content
rocky edited this page Dec 7, 2010 · 4 revisions

Why is stepping in Ruby debuggers a problem?

On the one hand, it is not uncommon for someone to complain that they were stepping along and the debugger stepped right over where they
wanted to stop. And then there is other end of the spectrum: in Ruby one can write in a streaming or functional style:

   self.products.map(&:categories).flatten.uniq

and this is a good thing. So here, one get complaints that stepping is just too tedious. Even with the traditional 3 variations of step:
“step into” or step, “step over” or next, and “step out” or finish.

I think it was in order to address this tedium that Kent Siblev added a “mode” called set force which forces stepping to stop at a new
line number.

In the trepanning debuggers, set force is now called set different. And I’ve added suffixes to the step commands to set the
mode for that one step. So step+ sets the “different” mode on for the one command no matter what the mode was. Likewise step- sets “different” mode off for the one command.

This helps but, in my own use I don’t think this goes far enough. And to go one level further is where Ruby 1.9.2 and rubinius diverge. In
Ruby 1.9.2, many system-implemented calls are C functions (like upto or _times"). So the way we can filter out those calls and returns is
by saying we want to skip C call/return events. Right now you can’t step within the assembly language instructions of a C function. However in Rubinius upto and times are written in Ruby.

So what done in the Rubinius trepanning debugger was to add a mechanism to filter methods by their source location. In Rubinius many of the built-in methods have a file locations that starts “kernel/”. Note that this filename is a relative path and is stored that way even
though other file names are generally stored as absolute file names. If it turns out there are other locations, I can easily more.

And as with C events in 1.9.2 one can switch the defaults. Finally Ishould note that stepping doesn’t change the way breakpoints work. You can always set a breakpoint on a 1.9.2 C function or a Rubinius kernel method; hitting a breakpoint is independent of any kind of stepping that is performed.