Let's look at them. So, the first one uses Raise with the string Try again. This
is not an exception. Though it won't raise that error, but it will raise an
exception because this is invalid code. Any invalid code raises some kind of
exception. And what this raises is a type error, which gets handled by this
handler, which raises a ZEroDivisionError with the string raise a ruckus, which
then gets handled by the outer try, by this handler, which prints out that
string. For the second one, well, this is an exception, so the Raise could work
with just that, but we're adding 3 to it. Exceptions don't have a plus
operation, so that's going to produce a type error, which will get handled here.
That's going to raise a ZeroDivisionError, which is also going to print Raise a
ruckus. That's distinct from the third example, where we're going to print
Raise. Now, we're going to call Raise with IO error, passing an a, so that's a
valid raise. It's going to raise the IO error exception that's not a type error,
so it won't be handled by this exception handler. But it is an exception, so
it'll be handled by this one, which raises a type error, which is the value of
the string associated with that exception, which is a and ruckus. And that gets
handled by this handler, which prints out a ruckus. And we already printed out
the Raise here. So, this one also prints out Raise or ruckus. Part of what this
example illustrates is how convoluted exceptions can make your code. So, please,
please, please don't ever actually write code like this unless you're trying to
confuse someone. And usually, when you're writing code, you shouldn't be trying
to confuse people.