Question

I was going through the Programming Ruby book and I'm having problems understanding the following concepts:

  1. The authors talk about "transient exceptions" that may occur in the code and then suggest a creation of your own exception object to handle them. I don't think I fully understand what a transient error is and when is it appropriate to make your own Exception object. He talks about it in Chapter 6 when he talks about defining exceptions:

For Example, certain types of network errors might be transient.Chapter 6.Page 97. Adding Information to exceptions.

  1. I'm also having a hard time getting around the usage of Catch and Throw in ruby. When is this better than raise and rescue?
Was it helpful?

Solution

Can you give us a page reference to the "transient exceptions" line?

In any case, you can create a new exception any time, and it's commonly good to do so so that you can transfer more information about the fault. This is particularly good when you have alow level exception and want to make it into something more meaningful to the user.

Throw/Catch in Ruby are really a kind of nonlocal goto, like setjmp/longjmp in C, but better behaved. You'd use it anytime you want to tranfer execution a long ways.

Obviously, for the same reason you don't want to use goto much, you don't want to do this. A big reason you might use it is in a case of a program that needs to stay running, so if you catch certain kinds of errors, you might dump the whole piece of work you're doing and go back to the start.


Okay, that doesn't seem to be on page 97 of either of the editions of the pickaxe book I've got, but I see what it means. ... oh, here it is, page 157 in the third edition.

First of all, on the business about "transient", there are some network problems that can occur, and then resolve themselves, say when the BOFH unplugs the network cable and plugs it back in. So, under some conditions, you might want to give it a few seconds to settle down and try again before panicking. how would you do that?

In this case, they have you define a new kind of exception. This is done just with inheritance:

class RetryException < RuntimeError
  # so this is a kind of RuntimeError which is a kind of Exception
  attr: ok_to_retry
  def initialize(ok_to_retry)
     @ok_to_retry
  end
end

so then if something goes wrong, you can raise on of these new retryable exceptions

raise RetryException.new(true), "transient read error"

which now sends something that is a kind of RuntimeError up the stack, but now has additional information attached to it, ie, a flag that says "yes, this can be retried."

NOw, here's a really nifty thing in Ruby: it has a built in capability of retrying some things. So, someplace up the stack, you have this code:

begin
   # do something that raises this exception
   do_something()
rescue RetryException => detail 
   # if the exception is one of these retryable ones, 
   # catch it here, but it in detail
   if detail.ok_to_retry  
      retry
   end
   # this means exactly the same as 'retry if detail.ok_to_retry`
   # from the book, btw

   # if it STILL doesn't work, send the exception on
   raise # just re-raises the last exception
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top