It's time to discuss exceptions.
The Problem with Exceptions
Exceptions in many languages have a problem: they violate encapsulation.
For example: suppose module A calls a subroutine in module B, which calls one in C and C throws exception X. Module B ignores X but A handles it. Now suppose we change C in module B to D, which throws exception Y. We now have to change A to handle Y instead of X. More than that, we have to go through every piece of code that uses B and makes sure that Y is handle instead of X.
But the problem is more involved than that. If another module, E, calls both B and C, then the handler for X needs to be divided into two: one for X form C and on for Y from B.
And to top things off, if A fails to catch Y, an error report is made and the apps dies. But the error just says an uncaught exception was created by D. It does not indicate where the correction needs to be made.
Changing C to D is not local; it violates encapsulation.
The solution is simple: exceptions can only be thrown to their immediate caller.
For the example above: A calls B which calls C. C throws X but B must catch it. Then B reformats it and re-throws it as its own exception, Z. A now handles Z instead of X.
If we made the change in B from C to D, then B must catch Y and re-throw it as Z. All the changes are in B. No other changes are needed. This is encapsulation. (Everyone is happy.☺)
And if B fails to catch Y, an error report is made saying D threw Y but B failed to catch it. The programmer realizes that a change must be made to B for the app to be happy again. Error reporting is more comprehensive. (Everyone is happy once again.☺)