No method should ever throw an exception that is implementation specific.
The LetExceptionsPropagate pattern can be used like this: whenever the compiler complains about an unhandled exception, let's add a throws clause. But then we have to change all callers, and their callers as well. Throws clauses shouldn't be taken lightly. Developers tend to neglect the fact that the throws clause (at least in Java) is an integral part of the signature, i.e. the contract of a method. Changing a throws clause is as tedious as changing the parameter list.
From the point of view of OO and encapsulation, any declared exception should make some sense to the caller. If the caller doesn't know that the service she uses depends on I/O-functionality, she shouldn't see an IOException. For example, a persistence interface must never propagate an SQLException or an IOException because the client doesn't care about the physical implementation of the datastore. Thus, if the interface receives an SQLException that it cannot handle it must convert it to its module-specific PersistenceException (or some subclass) which has been declared as part of its contract. Later changes to the implementation won't affect the interface's throws clauses. The original exception should be wrapped in to facilitate debugging and error diagnostics.
LetExceptionsPropagate can work fine within a defined module. But even within a module, every method signature should be defined carefully to reflect the purpose of the method. This is true not only for the parameters but also for the throws clause.
-- ToniMenninger?
On the other hand, one could remember that we have the wonderful tool of Polymorphism at our disposal - by using a deep exception tree, one can have both the implementation-specific exception and the general exception? Of course, the problem is that defining new exception classes is cumbersome... and at that point, you should start eyeing your language with suspicion. After all, the standard exception idiom
But your-favourite-language has handy mechanisms for defining delegate classes - a single business class can easily define a dozen delegate classes without feeling bloated. Why are exceptions treated as the bastard son of every language? They're slow, heavyweight coding constructs, when they need to be expressive systems that explain exactly what went wrong without resorting to dumping a description into a string on a generic exception (example: the DotNet library is horribly full of InvalidOperationExceptions).
A deep exception heirarchy means no need to catch-and-wrap over and over again, since your implementation-specific exceptions subclass the generic exceptions that a naive consumer will know how to handle, but at the same time provide all the information needed for an intelligent consumer.
I throw implementation specific exceptions. I also extend java.lang.error so that I don't have to mess with throw() clauses.
Contributors: MartinZarate, ToniMenninger?
See also: ConvertExceptions, HomogenizeExceptions, TranslateExceptions
However, see also: DontThrowGenericExceptions