> > II) Use catch/throw for control structures, use rescue/raise for
> >     communicating errors.
[...]
> >       catch (:done) do
> >         loop do
> >           # Note: prompt_and_read can throw :done
> >           first_name = prompt_and_read "First name"
> >           last_name  = prompt_and_read "Last name"
> >           phone      = prompt_and_read "Phone"
> > 
> >           myfile.puts first_name + "\t" + last_name + "\t" + phone
> >         end
> >       end
>
> Well, that's interesting! (I didn't knew this is possible.) 
> What would happen in case there's no :done in the caller?
> The longer I think about it the more I like it.

I'm afraid I disagree.  Usually, it's better to make exits from a loop
explicit.  Why is the comment ("# Note: prompt_and_read can throw
:done") necessary?  Because without it (and without examining the code
of prompt_and_read), the reader of the code can't tell where and when
the loop is exited.  This design obliges the reader to rely on
comments to get such important information as loop exits.  I think
it's a poor design, I'm afraid.  I would write

   loop do
      first_name, last_name, phone
      = prompt_and_read "First name", "Last name", "Phone" or break
      ....
   end

or something along the lines.  (Have I got the precedence of operators
correct?  If not, please add a pair of parens.)  If you add a comment
on what prompt_and_read does, so much the better.  But, comments are
unnecessary because returning nil on failure is a common idiom.

So I disagree with the general statement "Use catch/throw for control
structures", although I'm sure there are cases where catch/throw as a
control structure is a good solution.  I would say, "Use raise/rescue
for communicating errors, use catch/throw sparingly."  Or if you can
formulate cases for legitimate use of catch/throw, please replace
"sparingly" with your phrase.

My 2 yen (about 1.7 US cents).
Cheers,
Ryo