Michael Neumann wrote:

> Rescue is a keyword, raise a method. They are used for exception handling,
> catch/throw are two methods, and are used to escape from nested loops,

Thanks for the clarification.

> Don't know about "resume", but perhaps "retry" is what you want.
> "retry" executes the block that failed once again.

Yes, I know about retry, but that's not what I'm interested in. I want to 
be able to retry the method that raised the exception -- in the original 
context. Ruby's (apparent) semantics are to throw away the stack between 
where the exception was initially raised and the first exception handler. 
Because of this, it's impossible to examine the context, fix the error, and 
then resume the thread, and instead you have to have explicit exception 
handling constructs throughout your code. I realize that in a 
non-interactive environment, this isn't as interesting, and you have to add 
the explicit exception handling.

It's just that in Smalltalk you don't have to add exception handling when 
trying out your program. If you get an exception, you can fix the problem 
and resume right where the program left off. In other words, you can retry 
at the level of any of the blocks between where the exception was first 
raised and the (possibly global) exception handler.

>> One of the reasons that resume semantics are interesting in Smalltalk is
>> that you can (for instance) pop up a debugger on an exception, interact
>> with the system, and then resume execution of the program.
> 
> That should be possible with Ruby, too.

How would that be possible with no resume? Imagine wrapping a whole program 
that lacks explicit rescue clauses inside a single exception handler that 
brings up a debugger. If the stack contexts have already been thrown away 
by the unwind mechanism, how are you going to do anything but retry the 
_whole program_?

But this very model works (well) in Smalltalk -- by default the global 
exception handler pops up a window that allows you to enter a debugger, 
retry, or abort the thread.

>> I guess that Ruby isn't yet aimed at the kind of long-running and
>> interactive systems that Smalltalk excels at. For instance, I used to
>> write factory machine control software in Smalltalk. Without stopping the
>> machine, we could load new versions of methods into the system, stop
>> threads, debug them, and resume them, and otherwise maintain the system
>> without bringing it down.
> 
> Possible with Ruby, too.

Even pausing/single-stepping/resuming arbitrary threads? How?

> Ruby is as dynamic as Smalltalk is.
> No problem to load new methods at runtime, etc..

Yes, this is one of the reasons that Ruby's appealing to me.

>> Does Ruby offer this ability? It seems that the debugger hooks are in an
>> inconvenient place (via a command-line option); does this mean that one
>> cannot debug a running system that has not been started with the debug
>> flag? I realize that you could have a thread in which you could do evals,
>> but can you (for instance) pause a running thread, step through it a bit,
>> and then resume it?
> 
> Smalltalk runs a debugger by default (I guess). Ruby do not.
> That's because Smalltalk is mostly an IDE + language, where Ruby is just
> an interpreter.

I understand that. But given Ruby's reflection and GUI abilities, why 
wouldn't a native Ruby IDE be a good thing to have?

> But it should be possible to load a debugger at runtime. Just call
> anywhere in a Ruby program "require debug.rb". That should do it.

Good, I'll try that. How does the debugger actually set breakpoints? Does 
it wrap the method in question, is there a method that you can call for a 
breakpoint (as in Smalltalk), or is there some flag that the interpreter 
has to check for every instruction (as is the case in Perl)?

In Perl, running with the debugger has a signficant performance penalty 
because of the check for breakpoints. Given Ruby's ability to wrap methods, 
I could imagine that a Ruby debugger wouldn't need to slow down any.

Thanks for the input!