Ruby, an Exceptional Language

Based on the book Exceptional Ruby by Avdi Grimm, I have developed a strategy for how I should deal with exceptions in Ruby.

Being a very dynamic language, Ruby allows very flexible coding techniques. Exceptions are not an exception :).

When I am developing a library in Ruby I typically create one Error module and one StdError class. The Error module is a typical tag module and does not contain any methods.

Tag Module

The reason for the tag module is that I can use it to tag exceptions
occurring inside my library without having to wrap them in a nested
exception.

This is beautiful. I am scoping an internal error as my own. Since Ruby
is dynamic there is no need to declare a new class that wraps all the
methods in the StandarError I have access to them anyway. Duck typing
for the win!

A Nested Exception Class

In some cases the tag module is not enough. Perhaps the exception was
not created by another exception. In that case I need a real class since
it is not possible to raise modules. But while I am at it I usually make
the class a nested exception in order to simplify wrapping of other
exceptions if the need comes up. This is how I do that.

Notice that I don’t have to wrap the exception explicitly, since
I default the Exception to the last error that is stored in $!.

Now the only reason for me to want to create a Tapir::StdError apart
from it being misuse of my library is if I want to add additional information
to the exception that already occurred. In that case I may also want to
extend the Tapir::StdError and create an exception with additional
fields.

Throw – Catch

Ruby also has an alternative to raise and rescue called throw and
catch.

They should not be used as an alternative to exceptions, instead they are
escape continuations
that should be used to escape from nested control structures across
method calls. Powerful! Here is an example from Sinatra

Lovely!

Wrap up

This is how I use exceptions in Ruby now, thanks to ideas from the book.
Other good ideas from the book are the three guarantees:

  • The weak guarantee, if an exception is raised, the object will be in
    a consistent state.
  • The strong guarantee, if an exception is raised, the object will be
    left in its initial state.
  • The nothrow guarantee, no exceptions will be raised by this method.

And a nice way of categorizing exceptions based on three different
usages by the client. (My categories are not exactly the same as Avdis)

  • User Error, the client has used the library wrong.
  • Internal Error, something is wrong with the library. We are looking
    into the problem…
  • Transient Error, something is now working right now, but the same
    call may succeed in a while. It is a good idea to provide a period
    after whick the call will probably succeed.
    the client to try again.

It is a great book which contains a lot more information than I covered
here. Get it, it is well worth the money.

Leave a Reply